package uu.game.majiang.core.rule.paixing.gb;

import static uu.game.majiang.core.Pai.CHI_CENTER;
import static uu.game.majiang.core.Pai.CHI_LEFT;
import static uu.game.majiang.core.Pai.CHI_RIGHT;
import static uu.game.majiang.core.Pai.GANG_AN;
import static uu.game.majiang.core.Pai.GANG_DUIJIA;
import static uu.game.majiang.core.Pai.GANG_SHANGJIA;
import static uu.game.majiang.core.Pai.GANG_XIAJIA;
import static uu.game.majiang.core.Pai.HU_ZIJI;
import static uu.game.majiang.core.Pai.PENG_DUIJIA;
import static uu.game.majiang.core.Pai.PENG_SHANGJIA;
import static uu.game.majiang.core.Pai.PENG_XIAJIA;
import uu.game.majiang.core.Pai;
import uu.game.majiang.core.Pai.Hupai;
import uu.game.majiang.core.Pais;
import uu.game.majiang.core.rule.paixing.Paixing;

/**
 * 中国国家体育总局1998.7制定的竞赛用麻将规则中使用的牌型，即常说的国标麻将
 * 
 * <pre>
 * 共81种形式：
 * <style>table{border-collapse:collapse;}td{border:1px solid green;}.fan{background-color:#BAEB67;}</style>
 * <table>
 *       <tr class="fan"><td>88番</td><td></td></tr>
 *       <tr><td>大四喜</td><td>由四副风刻(杠)组成的和牌。不计圈风刻、门风刻、三风刻、碰碰和</td></tr>
 *       <tr><td>大三元</td><td>和牌中，有中发白三副刻。不计箭刻</td></tr>
 *       <tr><td>绿一色</td><td>由23468条及“发”字中的任何牌组成的顺子、刻子、将的和牌。不计混一色。如无“发”字，可计清一色</td></tr>
 *       <tr><td>九莲宝灯</td><td>由一种花色序数牌按1112345678999组成的特定牌型，不能吃碰杠，见同花色任何一张序数牌即成和牌。不计清一色</td></tr>
 *       <tr><td>四杠</td><td>四个杠</td></tr>
 *       <tr><td>连七对*</td><td>由一种花色序数牌组成序数相连的七个对的和牌。不计清一色、不求人、单钓</td></tr>
 *       <tr><td>十三幺*</td><td>由三种序数牌的19牌、七种字牌及其中一对作将组成的和牌。不计五门齐、不求人、单钓</td></tr>
 *       <tr class="fan"><td>64番</td><td></td></tr>
 *       <tr><td>清幺九</td><td>由序数牌19刻组成的和牌。不计碰碰和、同刻、无字</td></tr>
 *       <tr><td>小四喜</td><td>和牌时有风牌的三副刻及将牌。不计三风刻</td></tr>
 *       <tr><td>小三元</td><td>和牌时有箭牌的两副刻及将牌。不计箭刻</td></tr>
 *       <tr><td>字一色</td><td>由字牌的刻、将组成的和牌。不计碰碰和</td></tr>
 *       <tr><td>四暗刻</td><td>四个暗刻。不计门前清、碰碰和</td></tr>
 *       <tr><td>一色双龙会</td><td>一种花色的两个老少副，5为将牌。不计平和、七对、清一色</td></tr>
 *       <tr class="fan"><td>48番</td><td></td></tr>
 *       <tr><td>一色四节高</td><td>一种花色四副依次递增一位数的刻，不计一色三同顺、碰碰和</td></tr>
 *       <tr><td>一色四同顺</td><td>一种花色四副序数相同的顺，不计一色三节高、一般高、四归一</td></tr>
 *       <tr class="fan"><td>32番</td><td></td></tr>
 *       <tr><td>一色四步高</td><td>一种花色四副依次递增一位数或依次递增二位数的顺</td></tr>
 *       <tr><td>三杠</td><td>三个杠</td></tr>
 *       <tr><td>混幺九</td><td>由字牌和序数牌19的刻和将牌组成的和牌。不计碰碰和</td></tr>
 *       <tr class="fan"><td>24番</td><td></td></tr>
 *       <tr><td>七对*</td><td>由七个对组成和牌。不计不求人、单钓</td></tr>
 *       <tr><td>七星不靠*</td><td>必须有七个单张的东西南北中发白，加上三种花色，数位按147、258、369中的七张序数牌组成没有将牌的和牌。不计五门齐、不求人、单钓</td></tr>
 *       <tr><td>全双刻</td><td>由2、4、6、8序数牌的刻、将牌组成的和牌。不计碰碰和、断幺</td></tr>
 *       <tr><td>清一色</td><td>由一种花色的序数牌组成的和牌。不计无字</td></tr>
 *       <tr><td>一色三节高</td><td>和牌时有一种花色三副依次递增一位数字的刻。不计一色三同顺</td></tr>
 *       <tr><td>一色三同顺</td><td>和牌时有一种花色三副序数相同的顺。不计一色三节高</td></tr>
 *       <tr><td>全大</td><td>由序数牌789组成的顺、刻、将牌的和牌。不计无字</td></tr>
 *       <tr><td>全中</td><td>由序数牌456组成的顺、刻、将牌的和牌。不计断幺</td></tr>
 *       <tr><td>全小</td><td>由序数牌123组成的顺、刻、将牌的和牌。不计无字</td></tr>
 *       <tr class="fan"><td>16番</td><td></td></tr>
 *       <tr><td>清龙</td><td>和牌时，有一种花色123 456 789三抹牌</td></tr>
 *       <tr><td>三色双龙会</td><td>两种花色两个老少副、另一种花色5作将的和牌。不计喜相逢、老少副、无字、平和</td></tr>
 *       <tr><td>一色三步高</td><td>和牌时，有一种花色三副依次递增一位或依次递增二位数字的顺</td></tr>
 *       <tr><td>全带五</td><td>每副牌及将牌必须有5的序数牌。不计断幺</td></tr>
 *       <tr><td>三同刻</td><td>三个序数相同的刻</td></tr>
 *       <tr><td>三暗刻</td><td>三个暗刻</td></tr>
 *       <tr class="fan"><td>12番</td><td></td></tr>
 *       <tr><td>全不靠*</td><td>由单张三种花色147、258、369不能错位的序数牌及东南西北中发白中的任何十四张牌组成的和牌。不计五门齐、不求人、单钓</td></tr>
 *       <tr><td>组合龙*</td><td>三种花色的147、258、369不能错位的序数牌</td></tr>
 *       <tr><td>大于五</td><td>由序数牌6至9的顺、刻、将牌组成的和牌。不计无字</td></tr>
 *       <tr><td>小于五</td><td>由序数牌1至4的顺、刻、将牌组成的和牌。不计无字</td></tr>
 *       <tr><td>三风刻</td><td>三个风刻</td></tr>
 *       <tr class="fan"><td>8番</td><td></td></tr>
 *       <tr><td>花龙</td><td>三种花色的三副顺(123 456 789)连接成1至9的序数牌</td></tr>
 *       <tr><td>推不倒</td><td>由牌面图形没有上下区别的牌组成的和牌，包括1234589饼、245689条、白板。不计缺一门</td></tr>
 *       <tr><td>三色三节高</td><td>和牌时，有三种花色三副依次递增一位数的刻</td></tr>
 *       <tr><td>三色三同顺</td><td>和牌时，有三种花色三副序数相同的顺</td></tr>
 *       <tr><td>无番和</td><td>和牌后，数不出任何番种分(花牌不计算在内)</td></tr>
 *       <tr><td>妙手回春</td><td>自摸牌墙上最后一张牌和牌。不计自摸</td></tr>
 *       <tr><td>海底捞月</td><td>和别人打出的牌墙上最后一张牌</td></tr>
 *       <tr><td>杠上开花</td><td>开杠抓进的牌成和牌(不包括补花)，不计自摸</td></tr>
 *       <tr><td>抢杠和</td><td>和别人摸到并开明杠的牌。不计和绝张</td></tr>
 *       <tr class="fan"><td>6番</td><td></td></tr>
 *       <tr><td>碰碰和</td><td>由四副刻、将牌组成的和牌</td></tr>
 *       <tr><td>混一色</td><td>由一种花色序数牌及字牌组成的和牌</td></tr>
 *       <tr><td>三色三步高</td><td>三种花色三副依次递增一位序数的顺</td></tr>
 *       <tr><td>五门齐</td><td>和牌时三种序数牌、风、箭牌齐全</td></tr>
 *       <tr><td>全求人</td><td>全靠吃牌、碰牌、单钓别人出的牌和牌。不计单钓</td></tr>
 *       <tr><td>双暗杠</td><td>两个暗杠</td></tr>
 *       <tr><td>双箭刻</td><td>两副箭刻</td></tr>
 *       <tr class="fan"><td>4番</td><td></td></tr>
 *       <tr><td>全带幺</td><td>和牌时，每副牌、将牌都有幺九字牌</td></tr>
 *       <tr><td>不求人</td><td>四副牌及将中没有吃牌、碰牌、明杠(自摸和牌)</td></tr>
 *       <tr><td>双明杠</td><td>两个明杠</td></tr>
 *       <tr><td>和绝张</td><td>和牌池、桌面已亮明的三张牌所剩的第四张牌</td></tr>
 *       <tr class="fan"><td>2番</td><td></td></tr>
 *       <tr><td>箭刻</td><td>中发白的刻</td></tr>
 *       <tr><td>圈风刻</td><td>与圈风相同的风刻</td></tr>
 *       <tr><td>门风刻</td><td>与本门风相同的风刻</td></tr>
 *       <tr><td>门前清</td><td>没有吃、碰、明杠(和别人打出的牌)</td></tr>
 *       <tr><td>平和</td><td>由四副顺及序数牌作将组成的和牌，边、坎、钓不影响平和</td></tr>
 *       <tr><td>四归一</td><td>和牌中，有四张相同的牌(不包括杠牌)</td></tr>
 *       <tr><td>双同刻</td><td>两副序数相同的刻</td></tr>
 *       <tr><td>双暗刻</td><td>两个暗刻</td></tr>
 *       <tr><td>暗杠</td><td>自抓四张相同的牌开杠</td></tr>
 *       <tr><td>断幺</td><td>和牌中没有19及字牌</td></tr>
 *       <tr class="fan"><td>1番</td><td></td></tr>
 *       <tr><td>一般高</td><td>一种花色两副相同的顺</td></tr>
 *       <tr><td>喜相逢</td><td>两种花色两副序数相同的顺</td></tr>
 *       <tr><td>连六</td><td>一种花色六张相连接的序数牌组成两幅顺</td></tr>
 *       <tr><td>老少副</td><td>一种花色牌的123、789两副顺</td></tr>
 *       <tr><td>幺九刻</td><td>三张相同的19序数牌及字牌组成的刻</td></tr>
 *       <tr><td>明杠</td><td>自己有暗刻，碰别人打出的一张相同的牌开杠，或自己抓进一张与碰的明刻相同的牌开杠</td></tr>
 *       <tr><td>缺一门</td><td>和牌中缺少一种花色序数牌</td></tr>
 *       <tr><td>无字</td><td>和牌中没有风、箭牌</td></tr>
 *       <tr><td>边张</td><td>单和123的3及789的7或1233和3、 7789和7都为边张。手中有12345和3，56789和7不算边张</td></tr>
 *       <tr><td>坎张</td><td>和两张牌之间的牌。4556和5也为坎张，手中有45567和6不算坎张</td></tr>
 *       <tr><td>单钓将</td><td>钓单张牌作将成和</td></tr>
 *       <tr><td>自摸</td><td>自己抓进牌成和牌</td></tr>
 *       <tr><td>花牌</td><td>即春夏秋冬，梅兰竹菊，每花计一分。不计在起和分内，和牌后才能计分。花牌补花成和计自摸分，不计杠上开花</td></tr>
 * </table>
 * 
 * 另外：(TODO 下属规则有所变化，须最终完成时根据实际情况定稿)
 * 因为某些细节在国标规则中并没有详细说明，作者也没有找到相关资料，所以根据自己对牌型的理解，按照下面的附加原则进行匹配：
 *  1 基本原则是大番牌型必然包含的小番牌型不再计算在内(国标规则中也有所体现，但不全面)
 *  2 某张牌有多种组合方式时，按照番值最大来组合
 *  3 一抹牌已经在某种牌型中使用过，不能再与其它牌组成相同的牌型，但是可以组成不同的牌型
 *  3 对倒(手里两对)时自摸才算一个暗刻
 *  4 不是圈风、门风的风刻算作幺九刻
 *  5 九莲宝灯不能吃碰杠
 *  6 七对不计绿一色、清幺九、混幺九、全双刻、大中小系列等规则中明确指明需要顺、刻、将组成的牌型
 * </pre>
 * 
 * @author uu
 * @see Paixing
 * @see Pai
 * @see Hupai
 * @see GbPaixingAnalyser
 * @version 2010-4-29 下午12:10:37
 */
/*
 * 解析牌型时依赖于每个具体牌型在此枚举中定义的顺序，不要修改这个顺序
 * 
 * 使用枚举方便一些，但是需要每种牌型分别判断，必然存在很多重复的计算，效率肯定不如按照牌型的内在规律直接判断。 但是那样做逻辑会非常繁杂，所以牺牲一下效率。
 * 另外因为数据量小，所以大部分牌型都是穷举所有可能性判断的，这样逻辑清晰一些，并且可以避免一些重复判断
 * 在高番牌型的匹配开始时，有一些冗余判断，主要是为了尽早排除不满足的情况，因为相对来说满足(特别是满足高番牌型)的机会是比较小的
 */
public enum GbPaixing implements Paixing {

    /**
     * 大四喜(88)<br/>
     * <br/>
     * 由四副风刻(杠)组成的和牌。不计圈风刻、门风刻、三风刻、碰碰和
     */
    DA_SI_XI("大四喜", 88) {
        @Override
        public int match(Hupai hupai) {
            int[] data = hupai.getFullData();
            if (data[40] == 12)
                return 1;
            return 0;
        }
    },

    /**
     * 大三元(88)<br/>
     * <br/>
     * 和牌中，有中发白三副刻。不计箭刻
     */
    DA_SAN_YUAN("大三元", 88) {
        @Override
        public int match(Hupai hupai) {
            int[] data = hupai.getFullData();
            if (data[50] == 9)
                return 1;
            return 0;
        }
    },

    /**
     * 绿一色(88)<br/>
     * <br/>
     * 由23468条及“发”字中的任何牌组成的顺子、刻子、将的和牌。不计混一色。如无“发”字，可计清一色
     */
    LV_YI_SE("绿一色", 88) {
        @Override
        public int match(Hupai hupai) {
            int[] data = hupai.getFullData();
            if (data[10] == 0 && data[30] == 0 && data[40] == 0
             && data[21] == 0 && data[25] == 0 && data[27] == 0 && data[29] == 0
             && data[51] == 0 && data[53] == 0)
                return 1;
            return 0;
        }
    },

    /**
     * 九莲宝灯(88)<br/>
     * <br/>
     * 由一种花色序数牌按1112345678999组成的特定牌型，不能吃碰杠，见同花色任何一张序数牌即成和牌。不计清一色
     */
    JIU_LIAN_BAO_DENG("九莲宝灯", 88) {
        @Override
        public int match(Hupai hupai) {
            int[] data = hupai.getData();
            if (data[1] != 0)
                return 0;
            int p = hupai.getPaihao();
            data[p]--;
            boolean ok =    data[10] == 14
                         && data[11] == 3 && data[12] == 1 && data[13] == 1
                         && data[14] == 1 && data[15] == 1 && data[16] == 1
                         && data[17] == 1 && data[18] == 1 && data[19] == 3
                      ||    data[20] == 14
                         && data[21] == 3 && data[22] == 1 && data[23] == 1
                         && data[24] == 1 && data[25] == 1 && data[26] == 1
                         && data[27] == 1 && data[28] == 1 && data[29] == 3
                      ||    data[30] == 14
                         && data[31] == 3 && data[32] == 1 && data[33] == 1
                         && data[34] == 1 && data[35] == 1 && data[36] == 1
                         && data[37] == 1 && data[38] == 1 && data[39] == 3;
            data[p]++;
            return ok ? 1 : 0;
        }
    },

    /**
     * 四杠(88)<br/>
     * <br/>
     * 四个杠
     */
    SI_GANG("四杠", 88) {
        @Override
        public int match(Hupai hupai) {
            int[] data = hupai.getData();
            if (data[1] == 4 
             && isGang(data[2]) && isGang(data[4]) && isGang(data[6]) && isGang(data[8]))
                return 1;
            return 0;
        }
    },

    /**
     * 连七对(88)<br/>
     * <br/>
     * 由一种花色序数牌组成序数相连的七个对的和牌。不计清一色、不求人、单钓
     */
    LIAN_QI_DUI("连七对", 88, true) {
        @Override
        public int match(Hupai hupai) {
            int[] data = hupai.getData();
            if (data[1] == 0 
               && (data[10] == 14
                   &&  data[13] == 2 && data[14] == 2 && data[15] == 2
                   &&  data[16] == 2 && data[17] == 2
                   && (data[11] == 2 && data[12] == 2
                    || data[12] == 2 && data[18] == 2
                    || data[18] == 2 && data[19] == 2)
                || data[20] == 14
                   &&  data[23] == 2 && data[24] == 2 && data[25] == 2
                   &&  data[26] == 2 && data[27] == 2
                   && (data[21] == 2 && data[22] == 2
                    || data[22] == 2 && data[28] == 2
                    || data[28] == 2 && data[29] == 2)
                || data[30] == 14
                   &&  data[33] == 2 && data[34] == 2 && data[35] == 2
                   &&  data[36] == 2 && data[37] == 2
                   && (data[31] == 2 && data[32] == 2
                    || data[32] == 2 && data[38] == 2
                    || data[38] == 2 && data[39] == 2)))
                return 1;
            return 0;
        }
    },
    
    /**
     * 十三幺(88)<br/>
     * <br/>
     * 由三种序数牌的19牌、七种字牌及其中一对作将组成的和牌。不计五门齐、不求人、单钓
     */
    SHI_SAN_YAO("十三幺", 88, true) {
        @Override
        public int match(Hupai hupai) {
            int[] data = hupai.getData();
            if (data[1] != 0)
                return 0;
            int p = hupai.getPaihao();
            if (!Pais.isYaojiuzi(p))
                return 0;
            boolean jiang = false;
            int c = 0;
            for (int yjz : YAO_JIU_ZI) {
                c = data[yjz];
                if (c == 1)
                    continue;
                if (c == 2 && !jiang) {
                    jiang = true;
                    continue;
                }
                return 0;
            }
            return 1;
        }
    },

    /**
     * 清幺九(64)<br/>
     * <br/>
     * 由序数牌19刻组成的和牌。不计碰碰和、同刻、无字
     */
    QING_YAO_JIU("清幺九", 64) {
        @Override
        public int match(Hupai hupai) {
            int[] data = hupai.getData();
            if (data[46] == 0 // 没有顺
             && data[40] == 0 && data[50] == 0
             && Pais.isYaojiu(data[45])
             && Pais.isYaojiu(data[57])
             && Pais.isYaojiu(data[56])
             && Pais.isYaojiu(data[55])
             && Pais.isYaojiu(data[54]))
                return 1;
            return 0;
        }
    },

    /**
     * 小四喜(64)<br/>
     * <br/>
     * 和牌时有风牌的三副刻及将牌。不计三风刻
     */
    XIAO_SI_XI("小四喜", 64) {
        @Override
        public int match(Hupai hupai) {
            int[] data = hupai.getFullData();
            if (data[40] == 11)
                return 1;
            return 0;
        }
    },

    /**
     * 小三元(64)<br/>
     * <br/>
     * 和牌时有箭牌的两副刻及将牌。不计箭刻
     */
    XIAO_SAN_YUAN("小三元", 64) {
        @Override
        public int match(Hupai hupai) {
            int[] data = hupai.getFullData();
            if (data[50] == 8)
                return 1;
            return 0;
        }
    },

    /**
     * 字一色(64)<br/>
     * <br/>
     * 由字牌的刻、将组成的和牌。不计碰碰和
     */
    ZI_YI_SE("字一色", 64) {
        @Override
        public int match(Hupai hupai) {
            int[] data = hupai.getFullData();
            if (data[10] == 0 && data[20] == 0 && data[30] == 0)
                return 1;
            return 0;
        }
    },

    /**
     * 四暗刻(64)<br/>
     * <br/>
     * 四个暗刻。不计门前清、碰碰和
     */
    SI_AN_KE("四暗刻", 64) {
        @Override
        public int match(Hupai hupai) {
            int[] data = hupai.getData();
            for (int i = 2; data[i] != 0 && i <= 8; i += 2)
                if (!isAngang(data[i]))
                    return 0;
            if (data[57] != 0 // 四刻
            && (hupai.getPaihao() == data[45] // 和将
             || hupai.getType() == HU_ZIJI))  // 自摸
                return 1;
            return 0;
        }
    },

    /**
     * 一色双龙会(64)<br/>
     * <br/>
     * 一种花色的两个老少副，5为将牌。不计平和、七对、清一色
     */
    YI_SE_SHUANG_LONG_HUI("一色双龙会", 64) {
        @Override
        public int match(Hupai hupai) {
            int[] data = hupai.getData();
            if (data[49] != 0 // 四顺
             && (   data[45] == 15
                 && data[49] == 17 && data[48] == 17
                 && data[47] == 11 && data[46] == 11
              ||    data[45] == 25
                 && data[49] == 27 && data[48] == 27
                 && data[47] == 21 && data[46] == 21
              ||    data[45] == 35
                 && data[49] == 37 && data[48] == 37
                 && data[47] == 31 && data[46] == 31))
                return 1;
            return 0;
        }
    },

    /**
     * 一色四节高(48)<br/>
     * <br/>
     * 一种花色四副依次递增一位数的刻，不计一色三同顺、碰碰和
     */
    YI_SE_SI_JIE_GAO("一色四节高", 48) {
        @Override
        public int match(Hupai hupai) {
            int[] data = hupai.getData();
            int k1 = data[54];
            if (k1 > 36) // 最大6饼
                return 0;
            if (data[57] == k1 + 3 && data[56] == k1 + 2 && data[55] == k1 + 1)
                return 1;
            return 0;
        }
    },

    /**
     * 一色四同顺(48)<br/>
     * <br/>
     * 一种花色四副序数相同的顺，不计一色三节高、一般高、四归一
     */
    /*
     * 在解析是否满足基本和牌(33332形式)时，如果手里有如555566667777，那一色四同顺会解析成三个刻加一个顺，所以此处需特殊处理
     */
    YI_SE_SI_TONG_SHUN("一色四同顺", 48) {
        @Override
        public int match(Hupai hupai) {
            int[] data = hupai.getData();
            for (int i = 2; data[i] != 0 && i <= 8; i += 2)
                if (isPeng(data[i]) || isGang(data[i]))
                    return 0;
            int s1 = data[46];
            int s2 = data[47];
            int s3 = data[48];
            int s4 = data[49];
            int k1 = data[54];
            int k2 = data[55];
            int k3 = data[56];
            int k4 = data[57];
            if (k3 == k1 + 2 && k2 == k1 + 1
                && (s1 == k1 || s2 == k1 || s3 == k1 || s4 == k1)
             || k4 == k2 + 2 && k3 == k2 + 1
                && (s1 == k2 || s2 == k2 || s3 == k2 || s4 == k2)
             || s4 != 0 && s4 == s1 && s3 == s1 && s2 == s1)
                return 1;
            return 0;
        }
    },

    /**
     * 一色四步高(32)<br/>
     * <br/>
     * 一种花色四副依次递增一位数或依次递增二位数的顺
     */
    YI_SE_SI_BU_GAO("一色四步高", 32) {
        @Override
        public int match(Hupai hupai) {
            int[] data = hupai.getData();
            int s4 = data[49];
            if (s4 == 0) // 四顺
                return 0;
            int s1 = data[46];
            int s2 = data[47];
            int s3 = data[48];
            if (s2 == s1 + 1 && s3 == s1 + 2 && s4 == s1 + 3 // 123 234 345 456
             || s1 % 10 == 1 && s2 == s1 + 2 && s3 == s1 + 4 && s4 == s1 + 6) // 123 345 567 789
                return 1;
            return 0;
        }
    },

    /**
     * 三杠(32)<br/>
     * <br/>
     * 三个杠
     */
    SAN_GANG("三杠", 32) {
        @Override
        public int match(Hupai hupai) {
            int[] data = hupai.getData();
            if (data[56] == 0) // 三刻
                return 0;
            int n = 0;
            for (int i = 2; data[i] != 0 && i <= 8; i += 2)
                if (isGang(data[i]))
                    n++;
            if (n == 3)
                return 1;
            return 0;
        }
    },

    /**
     * 混幺九(32)<br/>
     * <br/>
     * 由字牌和序数牌19的刻和将牌组成的和牌。不计碰碰和
     */
    HUN_YAO_JIU("混幺九", 32) {
        @Override
        public int match(Hupai hupai) {
            int[] data = hupai.getData();
            if (data[46] == 0 // 没有顺
             && Pais.isYaojiuzi(data[45])
             && Pais.isYaojiuzi(data[57])
             && Pais.isYaojiuzi(data[56])
             && Pais.isYaojiuzi(data[55])
             && Pais.isYaojiuzi(data[54]))
                return 1;
            return 0;
        }
    },

    /**
     * 七对(24)<br/>
     * <br/>
     * 由七个对组成和牌。不计不求人、单钓
     */
    QI_DUI("七对", 24, true) {
        @Override
        public int match(Hupai hupai) {
            int[] data = hupai.getData();
            if (data[1] != 0)
                return 0;
            if (YI_SE_SHUANG_LONG_HUI.match(hupai) > 0
             || YI_SE_SI_TONG_SHUN.match(hupai) > 0)
                return 0;
            int p = 11;
            int pc = 0;
            for (p = 11; p <= 19; p++) {
                pc = data[p];
                if (pc != 0 && pc != 2 && pc != 4)
                    return 0;
            }
            for (p = 21; p <= 29; p++) {
                pc = data[p];
                if (pc != 0 && pc != 2 && pc != 4)
                    return 0;
            }
            for (p = 31; p <= 39; p++) {
                pc = data[p];
                if (pc != 0 && pc != 2 && pc != 4)
                    return 0;
            }
            for (p = 41; p <= 44; p++) {
                pc = data[p];
                if (pc != 0 && pc != 2 && pc != 4)
                    return 0;
            }
            for (p = 51; p <= 53; p++) {
                pc = data[p];
                if (pc != 0 && pc != 2 && pc != 4)
                    return 0;
            }
            return 1;
        }
    },

    /**
     * 七星不靠(24)<br/>
     * <br/>
     * 必须有七个单张的东西南北中发白，加上三种花色，数位按147、258、369中的七张序数牌组成没有将牌的和牌。不计五门齐、不求人、单钓
     */
    QI_XING_BU_KAO("七星不靠", 24, true) {
        @Override
        public int match(Hupai hupai) {
            int[] data = hupai.getData();
            if (data[1] != 0
             || data[40] != 4 // 四风
             || data[50] != 3 // 三箭
             || data[10] + data[20] + data[30] != 7)
                return 0;
            // 东南西北中发白恰好各有一张，万条饼加起来7张，并组合出 147 258 369之一
            if (quanBukaoCountFengJian(data) == 7 && bukaoCountWanTiaoBing(data) == 7)
                return 1;
            return 0;
        }
    },

    /**
     * 全双刻(24)<br/>
     * <br/>
     * 由2、4、6、8序数牌的刻、将牌组成的和牌。不计碰碰和、断幺
     */
    QUAN_SHUANG_KE("全双刻", 24) {
        @Override
        public int match(Hupai hupai) {
            int[] data = hupai.getFullData();
            if (data[57] != 0 // 四刻
             && data[40] == 0 && data[50] == 0
             && data[11] == 0 && data[13] == 0 && data[15] == 0 && data[17] == 0 && data[19] == 0
             && data[21] == 0 && data[23] == 0 && data[25] == 0 && data[27] == 0 && data[29] == 0
             && data[31] == 0 && data[33] == 0 && data[35] == 0 && data[37] == 0 && data[39] == 0)
                return 1;
            return 0;
        }
    },

    /**
     * 清一色(24)<br/>
     * <br/>
     * 由一种花色的序数牌组成的和牌。不计无字
     */
    QING_YI_SE("清一色", 24) {
        @Override
        public int match(Hupai hupai) {
            int[] data = hupai.getFullData();
            if (data[10] == 14 || data[20] == 14 || data[30] == 14)
                return 1;
            return 0;
        }
    },

    /**
     * 一色三节高(24)<br/>
     * <br/>
     * 和牌时有一种花色三副依次递增一位数字的刻。不计一色三同顺
     */
    YI_SE_SAN_JIE_GAO("一色三节高", 24) {
        @Override
        public int match(Hupai hupai) {
            int[] data = hupai.getData();
            int k3 = data[56];
            if (k3 == 0 || k3 > 39) // 三刻，最大9饼
                return 0;
            int k1 = data[54];
            int k2 = data[55];
            int k4 = data[57];
            if (k3 == k1 + 2 && k2 == k1 + 1 // 111 222 333 xxx
             || k4 == k2 + 2 && k3 == k2 + 1)// xxx 111 222 333
                return 1;
            return 0;
        }
    },

    /**
     * 一色三同顺(24)<br/>
     * <br/>
     * 和牌时有一种花色三副序数相同的顺。不计一色三节高
     */
    /*
     * 不包括吃碰杠的牌中如果有333444555形式的牌时，一色三同顺和一色三节高是无法区分的，按照国标准则，上述情况算作一色三节高
     */
    YI_SE_SAN_TONG_SHUN("一色三同顺", 24) {
        @Override
        public int match(Hupai hupai) {
            int[] data = hupai.getData();
            int s3 = data[48];
            if (s3 == 0) // 三顺
                return 0;
            int s1 = data[46];
            int s2 = data[47];
            int s4 = data[49];
            if (s3 == s1 && s2 == s1 || s4 == s2 && s3 == s2)
                return 1;
            return 0;
        }
    },

    /**
     * 全大(24)<br/>
     * <br/>
     * 由序数牌789组成的顺、刻、将牌的和牌。不计无字
     */
    QUAN_DA("全大", 24) {
        @Override
        public int match(Hupai hupai) {
            int[] data = hupai.getFullData();
            if (   data[40] == 0 && data[50] == 0
                && data[11] == 0 && data[12] == 0 && data[13] == 0
                && data[14] == 0 && data[15] == 0 && data[16] == 0
                && data[21] == 0 && data[22] == 0 && data[23] == 0
                && data[24] == 0 && data[25] == 0 && data[26] == 0
                && data[31] == 0 && data[32] == 0 && data[33] == 0
                && data[34] == 0 && data[35] == 0 && data[36] == 0)
                return 1;
            return 0;
        }
    },

    /**
     * 全中(24)<br/>
     * <br/>
     * 由序数牌456组成的顺、刻、将牌的和牌。不计无字
     */
    QUAN_ZHONG("全中", 24) {
        @Override
        public int match(Hupai hupai) {
            int[] data = hupai.getFullData();
            if (   data[40] == 0 && data[50] == 0
                && data[11] == 0 && data[12] == 0 && data[13] == 0
                && data[17] == 0 && data[18] == 0 && data[19] == 0
                && data[21] == 0 && data[22] == 0 && data[23] == 0
                && data[27] == 0 && data[28] == 0 && data[29] == 0
                && data[31] == 0 && data[32] == 0 && data[33] == 0
                && data[37] == 0 && data[38] == 0 && data[39] == 0)
                return 1;
            return 0;
        }
    },

    /**
     * 全小(24)<br/>
     * <br/>
     * 由序数牌123组成的顺、刻、将牌的和牌。不计无字
     */
    QUAN_XIAO("全小", 24) {
        @Override
        public int match(Hupai hupai) {
            int[] data = hupai.getFullData();
            if (   data[40] == 0 && data[50] == 0
                && data[14] == 0 && data[15] == 0 && data[16] == 0
                && data[17] == 0 && data[18] == 0 && data[19] == 0
                && data[24] == 0 && data[25] == 0 && data[26] == 0
                && data[27] == 0 && data[28] == 0 && data[29] == 0
                && data[34] == 0 && data[35] == 0 && data[36] == 0
                && data[37] == 0 && data[38] == 0 && data[39] == 0)
                return 1;
            return 0;
        }
    },

    /**
     * 清龙(16)<br/>
     * <br/>
     * 和牌时，有一种花色123 456 789三抹牌
     */
    QING_LONG("清龙", 16) {
        @Override
        public int match(Hupai hupai) {
            int[] data = hupai.getData();
            int s3 = data[48];
            if (s3 == 0) // 三顺
                return 0;
            int s1 = data[46];
            int s2 = data[47];
            int s4 = data[49];
            if (s3 == 17 && s2 == 14 && s1 == 11 // 123w 456w 789w xxxx
             || s4 == 17 && s2 == 14 && s1 == 11 // 123w 456w xxxw 789w
             || s4 == 17 && s3 == 14 && s1 == 11 // 123w xxxw 456w 789w
             || s3 == 27 && s2 == 24 && s1 == 21 // 123t 456t 789t xxxx
             || s4 == 27 && s2 == 24 && s1 == 21 // 123t 456t xxxt 789t
             || s4 == 27 && s3 == 24 && s1 == 21 // 123t xxxt 456t 789t
             || s4 == 27 && s3 == 24 && s2 == 21 // xxxx 123t 456t 789t
             || s3 == 37 && s2 == 34 && s1 == 31 // 123b 456b 789b xxxb
             || s4 == 37 && s2 == 34 && s1 == 31 // 123b 456b xxxb 789b
             || s4 == 37 && s3 == 34 && s1 == 31 // 123b xxxb 456b 789b
             || s4 == 37 && s3 == 34 && s2 == 31)// xxxx 123b 456b 789b
                return 1;
            return 0;
        }
    },

    /**
     * 三色双龙会(16)<br/>
     * <br/>
     * 两种花色两个老少副、另一种花色5作将的和牌。不计喜相逢、老少副、无字、平和
     */
    SAN_SE_SHUANG_LONG_HUI("三色双龙会", 16) {
        @Override
        public int match(Hupai hupai) {
            int[] data = hupai.getFullData();
            if (data[40] != 0 || data[50] != 0) // 无字
                return 0;
            int j = data[45];
            if (j != 15 && j != 25 && j != 35) // 将是5
                return 0;
            int s4 = data[49];
            if (s4 == 0) // 四顺
                return 0;
            int s1 = data[46];
            int s2 = data[47];
            int s3 = data[48];
            if (j == 15 && s1 == 21 && s2 == 27 && s3 == 31 && s4 == 37 // 55w 123t 789t 123b 789b
             || j == 25 && s1 == 11 && s2 == 17 && s3 == 31 && s4 == 37 // 123w 789w 55t 123b 789b
             || j == 35 && s1 == 11 && s2 == 17 && s3 == 21 && s4 == 27)// 123w 789w 123t 789t 55b
                return 1;
            return 0;
        }
    },

    /**
     * 一色三步高(16)<br/>
     * <br/>
     * 和牌时，有一种花色三副依次递增一位或依次递增二位数字的顺
     */
    /*
     * 实际上有可能出现两个一色三步高，如123 234 345 567
     * 这种情况标准中并没有明确说明该算几个
     * 联众等都是只算一个，此处参照联众，也只算一个
     */
    YI_SE_SAN_BU_GAO("一色三步高", 16) {
        @Override
        public int match(Hupai hupai) {
            int[] data = hupai.getData();
            int s3 = data[48];
            if (s3 == 0) // 三顺
                return 0;
            int s1 = data[46];
            int s2 = data[47];
            int s4 = data[49];
            int s11 = s1 + 1;
            int s12 = s1 + 2;
            int s14 = s1 + 4;
            if (s3 == s12 && s2 == s11       // 123 234 345 xxx
             || s4 == s12 && s3 == s11       // 123 234 234 345
             || s4 == s2 + 2 && s3 == s2 + 1 // xxx 123 234 345
             || s3 == s14 && s2 == s12       // 123 345 567 xxx
             || s4 == s14 && s2 == s12       // 123 345 xxx 567
             || s4 == s14 && s3 == s12       // 123 xxx 345 567
             || s4 == s2 + 4 && s3 == s2 + 2)// xxx 123 345 567
                return 1;
            return 0;
        }
    },

    /**
     * 全带五(16)<br/>
     * <br/>
     * 每副牌及将牌必须有5的序数牌。不计断幺
     */
    QUAN_DAI_WU("全带五", 16) {
        @Override
        public int match(Hupai hupai) {
            int[] data = hupai.getData();
            int p = data[45];
            if (p != 15 && p != 25 && p != 35) // 将是5
                return 0;
            for (int i = 57; i >= 54; i--) {
                p = data[i];
                if (p != 0 && p != 15 && p != 25 && p != 35) // 刻是5
                    return 0;
            }
            for (int i = 49; i >= 46; i--) {
                p = data[i];
                if (p != 0 && p != 13 && p != 14 && p != 15
                           && p != 23 && p != 24 && p != 25
                           && p != 33 && p != 34 && p != 35) // 顺是345开头
                    return 0;
            }
            return 1;
        }
    },

    /**
     * 三同刻(16)<br/>
     * <br/>
     * 三个序数相同的刻
     */
    SAN_TONG_KE("三同刻", 16) {
        @Override
        public int match(Hupai hupai) {
            int[] data = hupai.getData();
            int k3 = data[56];
            if (k3 == 0 || k3 > 39) // 三刻，最大9饼
                return 0;
            int k1 = data[54];
            int k2 = data[55];
            int k4 = data[57];
            int k11 = k1 + 10;
            int k12 = k1 + 20;
            if (k2 == k11 && k3 == k12  // 111w 111t 111b xxxx
             || k4 != 0 && k4 <= 39
                && (k2 == k11 && k4 == k12 // 111w 111t xxxx 111b
                 || k3 == k11 && k4 == k12 // 111w xxxx 111t 111b
                 || k3 == k2 + 10 && k4 == k2 + 20)) // xxxx 111w 111t 111b
                return 1;
            return 0;
        }
    },

    /**
     * 三暗刻(16)<br/>
     * <br/>
     * 三个暗刻
     */
    SAN_AN_KE("三暗刻", 16) {
        @Override
        public int match(Hupai hupai) {
            int[] data = hupai.getFullData();
            if (data[56] == 0) // 三刻
                return 0;
            int gp = 0;
            for (int i = 2; data[i] != 0 && i <= 8; i += 2)
                if (isPeng(data[i]) || isMinggang(data[i]))
                    gp++;
            int k4 = data[57];
            if (k4 == 0 && gp == 0 || k4 != 0 && gp == 1) {
                int p = hupai.getPaihao();
                if (p == data[45] // 和将
                 || hupai.getType() == HU_ZIJI // 自摸
                 || data[54] != p && data[55] != p && data[56] != p && data[57] != p // 不是和的刻牌
                 || data[p] == 4) // 和的刻牌，但是是 33345和3，算一暗刻
                return 1;
            }
            return 0;
        }
    },

    /**
     * 全不靠(12)<br/>
     * <br/>
     * 由单张三种花色147、258、369不能错位的序数牌及东南西北中发白中的任何十四张牌组成的和牌。不计五门齐、不求人、单钓
     */
    QUAN_BU_KAO("全不靠", 12, true) {
        @Override
        public int match(Hupai hupai) {
            int[] data = hupai.getData();
            if (data[1] != 0)
                return 0;
            int fj = quanBukaoCountFengJian(data);
            if (fj < 5)
                return 0;
            if (bukaoCountWanTiaoBing(data) + fj == 14)
                return 1;
            return 0;
        }
    },

    /**
     * 组合龙(12)<br/>
     * <br/>
     * 三种花色的147、258、369不能错位的序数牌
     */
    ZU_HE_LONG("组合龙", 12, true) {
        @Override
        public int match(Hupai hupai) {
            int[] data = hupai.getData();
            if (data[1] > 1)
                return 0;
            int[] zhl = lookup(data);
            if (zhl.length == 0)
                return 0;
            if (quanBukaoCountFengJian(data) == 5)
                return 1; // 全不靠 + 组合龙
            remove(data, zhl);
            boolean ok = hupai.canHuBase();
            add(data, zhl);
            return ok ? 1 : 0;
        }

        /*
         * 找出组合龙来
         */
        private int[] lookup(int[] data) {
            if (data[11] != 0 && data[14] != 0 && data[17] != 0) {
                if (data[22] != 0 && data[25] != 0 && data[28] != 0
                 && data[33] != 0 && data[36] != 0 && data[39] != 0)
                    return new int[] { 11, 14, 17, 22, 25, 28, 33, 36, 39 }; // 147w 258t 369b
                if (data[23] != 0 && data[26] != 0 && data[29] != 0
                 && data[32] != 0 && data[35] != 0 && data[38] != 0)
                    return new int[] { 11, 14, 17, 23, 26, 29, 32, 35, 38 }; // 147w 369t 258b
            }
            if (data[12] != 0 && data[15] != 0 && data[18] != 0) {
                if (data[21] != 0 && data[24] != 0 && data[27] != 0
                 && data[33] != 0 && data[36] != 0 && data[39] != 0)
                    return new int[] { 12, 15, 18, 21, 24, 27, 33, 36, 39 }; // 258w 147t 369b
                if (data[23] != 0 && data[26] != 0 && data[29] != 0 
                 && data[31] != 0 && data[34] != 0 && data[37] != 0)
                    return new int[] { 12, 15, 18, 23, 26, 29, 31, 34, 37 }; // 258w 369t 147b
            }
            if (data[13] != 0 && data[16] != 0 && data[19] != 0) {
                if (data[21] != 0 && data[24] != 0 && data[27] != 0
                 && data[32] != 0 && data[35] != 0 && data[38] != 0)
                    return new int[] { 13, 16, 19, 21, 24, 27, 32, 35, 38 }; // 369w 147t 258b
                if (data[22] != 0 && data[25] != 0 && data[28] != 0
                 && data[31] != 0 && data[34] != 0 && data[37] != 0)
                    return new int[] { 13, 16, 19, 22, 25, 28, 31, 34, 37 }; // 369w 258t 147b
            }
            return new int[0];
        }
        
        /*
         * 把组合龙对应的9张牌从data中去掉，这样只剩5张牌，方便后面判断是否和牌
         */
        private void remove(int[] data, int[] zhl) {
            for (int p : zhl)
                data[p]--;
            data[10] -= 3;
            data[20] -= 3;
            data[30] -= 3;
        }
        
        /*
         * 把组合龙对应的9张牌补回data
         */
        private void add(int[] data, int[] zhl) {
            for (int p : zhl)
                data[p]++;
            data[10] += 3;
            data[20] += 3;
            data[30] += 3;
        }
    },

    /**
     * 大于五(12)<br/>
     * <br/>
     * 由序数牌6至9的顺、刻、将牌组成的和牌。不计无字
     */
    DA_YU_WU("大于五", 12) {
        @Override
        public int match(Hupai hupai) {
            int[] data = hupai.getFullData();
            if (   data[40] == 0 && data[50] == 0
                && data[11] == 0 && data[12] == 0 && data[13] == 0 && data[14] == 0 && data[15] == 0
                && data[21] == 0 && data[22] == 0 && data[23] == 0 && data[24] == 0 && data[25] == 0
                && data[31] == 0 && data[32] == 0 && data[33] == 0 && data[34] == 0 && data[35] == 0)
                return 1;
            return 0;
        }
    },

    /**
     * 小于五(12)<br/>
     * <br/>
     * 由序数牌1至4的顺、刻、将牌组成的和牌。不计无字
     */
    XIAO_YU_WU("小于五", 12) {
        @Override
        public int match(Hupai hupai) {
            int[] data = hupai.getFullData();
            if (   data[40] == 0 && data[50] == 0
                && data[15] == 0 && data[16] == 0 && data[17] == 0 && data[18] == 0 && data[19] == 0
                && data[25] == 0 && data[26] == 0 && data[27] == 0 && data[28] == 0 && data[29] == 0
                && data[35] == 0 && data[36] == 0 && data[37] == 0 && data[38] == 0 && data[39] == 0)
                return 1;
            return 0;
        }
    },

    /**
     * 三风刻(12)<br/>
     * <br/>
     * 三个风刻
     */
    SAN_FENG_KE("三风刻", 12) {
        @Override
        public int match(Hupai hupai) {
            int[] data = hupai.getFullData();
            if (data[40] == 9)
                return 1;
            return 0;
        }
    },

    /**
     * 花龙(8)<br/>
     * <br/>
     * 三种花色的三副顺(123 456 789)连接成1至9的序数牌
     */
    HUA_LONG("花龙", 8) {
        @Override
        public int match(Hupai hupai) {
            int[] data = hupai.getData();
            int s3 = data[48];
            if (s3 == 0) // 至少3顺
                return 0;
            int s1 = data[46];
            int s2 = data[47];
            int s4 = data[49];
            if (s1 == 11 
                && ((s2 == 24 && (s3 == 37         // 123w 456t 789b xxxx
                               || s4 == 37)        // 123w 456t xxxx 789b
                  || s3 == 24 && s4 == 37)         // 123w xxxx 456t 789b
                 || (s2 == 27 && (s3 == 34         // 123w 789t 456b xxxx
                               || s4 == 34)        // 123w 789t xxxx 456b
                  || s3 == 27 && s4 == 34))        // 123w xxxx 789t 456b
             || s2 == 11 && (s3 == 24 && s4 == 37  // xxxx 123w 456t 789b
                          || s3 == 27 && s4 == 34) // xxxx 123w 789t 456b
             || s1 == 14
                && ((s2 == 21 && (s3 == 37         // 456w 123t 789b xxxx
                               || s4 == 37)        // 456w 123t xxxx 789b
                  || s3 == 21 && s4 == 37)         // 456w xxxx 123t 789b
                 || (s2 == 27 && (s3 == 31         // 456w 789t 123b xxxx
                               || s4 == 31)        // 456w 789t xxxx 123b
                  || s3 == 27 && s4 == 31))        // 456w xxxx 789t 123b
             || s2 == 14 && (s3 == 21 && s4 == 37  // xxxx 456w 123t 789b
                          || s3 == 27 && s4 == 31) // xxxx 456w 789t 123b
             || s1 == 17
                && ((s2 == 21 && (s3 == 34         // 789w 123t 456b xxxx
                               || s4 == 34)        // 789w 123t xxxx 456b
                  || s3 == 21 && s4 == 34)         // 789w xxxx 123t 456b
                 || (s2 == 24 && (s3 == 31         // 789w 456t 123b xxxx
                               || s4 == 31)        // 789w 456t xxxx 123b
                  || s3 == 24 && s4 == 31))        // 789w xxxx 456t 123b
             || s2 == 17 && (s3 == 21 && s4 == 34  // xxxx 789w 123t 456b
                          || s3 == 24 && s4 == 31))// xxxx 789w 456t 123b
                return 1;
            return 0;
        }
    },

    /**
     * 推不倒(8)<br/>
     * <br/>
     * 由牌面图形没有上下区别的牌组成的和牌，包括1234589饼、245689条、白板。不计缺一门
     */
    TUI_BU_DAO("推不倒", 8) {
        @Override
        public int match(Hupai hupai) {
            int[] data = hupai.getFullData();
            if (data[10] == 0 && data[40] == 0
             && data[21] == 0 && data[23] == 0 && data[27] == 0
             && data[36] == 0 && data[37] == 0
             && data[51] == 0 && data[52] == 0)
                return 1;
            return 0;
        }
    },

    /**
     * 三色三节高(8)<br/>
     * <br/>
     * 和牌时，有三种花色三副依次递增一位数的刻
     */
    SAN_SE_SAN_JIE_GAO("三色三节高", 8) {
        @Override
        public int match(Hupai hupai) {
            int[] data = hupai.getData();
            int k3 = data[56];
            if (k3 == 0 || k3 > 39) // 至少3刻
                return 0;
            int k1 = data[54];
            int k2 = data[55];
            int k4 = data[57];
            if (isSanJieGao(k1, k2, k3)
             || k4 != 0 && k4 <= 39
                && (isSanJieGao(k1, k2, k4)
                 || isSanJieGao(k1, k3, k4)
                 || isSanJieGao(k2, k3, k4)))
                return 1;
            return 0;
        }
        
        private boolean isSanJieGao(int w, int t, int b) {
            return Pais.isWan(w) && Pais.isTiao(t) && Pais.isBing(b)
                && (t == w + 11 && b == w + 22  // 444w 555t 666b
                 || t == w + 12 && b == w + 21  // 444w 666t 555b
                 || t == w + 9  && b == w + 21  // 555w 444t 666b
                 || t == w + 8  && b == w + 19  // 666w 444t 555b
                 || t == w + 11 && b == w + 19  // 555w 666t 444b
                 || t == w + 9  && b == w + 18);// 666w 555t 444b
        }
    },

    /**
     * 三色三同顺(8)<br/>
     * <br/>
     * 和牌时，有三种花色三副序数相同的顺
     */
    SAN_SE_SAN_TONG_SHUN("三色三同顺", 8) {
        @Override
        public int match(Hupai hupai) {
            int[] data = hupai.getData();
            int s3 = data[48];
            if (s3 == 0) // 至少3顺
                return 0;
            int s1 = data[46];
            int s2 = data[47];
            int s4 = data[49];
            int s11 = s1 + 10;
            int s12 = s1 + 20;
            if (s3 == s12 && s2 == s11  // 123w 123t 123b xxxx
             || s4 != 0 && (s4 == s12 && s2 == s11 // 123w 123t xxxx 123b
                         || s4 == s12 && s3 == s11 // 123w xxxx 123t 123b
                         || s4 == s2 + 20 && s3 == s2 + 10)) // xxxx 123w 123t 123b
                return 1;
            return 0;
        }
    },

    /**
     * 妙手回春(8)<br/>
     * <br/>
     * 自摸牌墙上最后一张牌和牌。不计自摸
     */
    MIAO_SHOU_HUI_CHUN("妙手回春", 8) {
        @Override
        public int match(Hupai hupai) {
            if (hupai.isLast() && hupai.getType() == HU_ZIJI)
                return 1;
            return 0;
        }
    },

    /**
     * 海底捞月(8)<br/>
     * <br/>
     * 和别人打出的牌墙上最后一张牌
     */
    HAI_DI_LAO_YUE("海底捞月", 8) {
        @Override
        public int match(Hupai hupai) {
            if (hupai.isLast() && hupai.getType() != HU_ZIJI)
                return 1;
            return 0;
        }
    },

    /**
     * 杠上开花(8)<br/>
     * <br/>
     * 开杠抓进的牌成和牌(不包括补花)，不计自摸
     */
    GANG_SHANG_KAI_HUA("杠上开花", 8) {
        @Override
        public int match(Hupai hupai) {
            return hupai.isGangbu() ? 1 : 0;
        }
    },

    /**
     * 抢杠和(8)<br/>
     * <br/>
     * 和别人摸到并开明杠的牌。不计和绝张
     */
    QIANG_GANG_HU("抢杠和", 8) {
        @Override
        public int match(Hupai hupai) {
            return hupai.isQianggang() ? 1 : 0;
        }
    },

    /**
     * 碰碰和(6)<br/>
     * <br/>
     * 由四副刻、将牌组成的和牌
     */
    PENG_PENG_HU("碰碰和", 6) {
        @Override
        public int match(Hupai hupai) {
            int[] data = hupai.getData();
            if (data[57] != 0) // 四刻
                return 1;
            return 0;
        }
    },

    /**
     * 混一色(6)<br/>
     * <br/>
     * 由一种花色序数牌及字牌组成的和牌
     */
    HUN_YI_SE("混一色", 6) {
        @Override
        public int match(Hupai hupai) {
            int[] data = hupai.getFullData();
            if ((data[40] != 0 || data[50] != 0)
             && (data[10] != 0 && data[20] == 0 && data[30] == 0
              || data[10] == 0 && data[20] != 0 && data[30] == 0
              || data[10] == 0 && data[20] == 0 && data[30] != 0))
                return 1;
            return 0;
        }
    },

    /**
     * 三色三步高(6)<br/>
     * <br/>
     * 三种花色三副依次递增一位序数的顺
     */
    SAN_SE_SAN_BU_GAO("三色三步高", 6) {
        @Override
        public int match(Hupai hupai) {
            int[] data = hupai.getData();
            int s3 = data[48];
            if (s3 == 0) // 至少3顺
                return 0;
            int s1 = data[46];
            int s2 = data[47];
            int s4 = data[49];
            if (isSanBuGao(s1, s2, s3)
             || s4 != 0
                && (isSanBuGao(s1, s2, s4)
                 || isSanBuGao(s1, s3, s4)
                 || isSanBuGao(s2, s3, s4)))
                return 1;
            return 0;
        }
        
        private boolean isSanBuGao(int w, int t, int b) {
            return Pais.isWan(w) && Pais.isTiao(t) && Pais.isBing(b)
                && (t == w + 11 && b == w + 22  // 123w 234t 345b
                 || t == w + 12 && b == w + 21  // 123w 345t 234b
                 || t == w + 9  && b == w + 21  // 234w 123t 345b
                 || t == w + 8  && b == w + 19  // 345w 123t 234b
                 || t == w + 11 && b == w + 19  // 234w 345t 123b
                 || t == w + 9  && b == w + 18);// 345w 234t 123b
        }
    },

    /**
     * 五门齐(6)<br/>
     * <br/>
     * 和牌时三种序数牌、风、箭牌齐全
     */
    WU_MEN_QI("五门齐", 6) {
        @Override
        public int match(Hupai hupai) {
            int[] data = hupai.getFullData();
            if (data[50] != 0 && data[40] != 0 
             && data[30] != 0 && data[20] != 0 && data[10] != 0)
                return 1;
            return 0;
        }
    },

    /**
     * 全求人(6)<br/>
     * <br/>
     * 全靠吃牌、碰牌、单钓别人出的牌和牌。不计单钓
     */
    QUAN_QIU_REN("全求人", 6) {
        @Override
        public int match(Hupai hupai) {
            int[] data = hupai.getData();
            if (data[1] != 4)
                return 0;
            if (hupai.getType() == HU_ZIJI)
                return 0;
            for (int i = 2; data[i] != 0 && i <= 8; i += 2)
                if (isAngang(data[i]))
                    return 0;
            return 1;
        }
    },

    /**
     * 双暗杠(6)<br/>
     * <br/>
     * 两个暗杠
     */
    SHUANG_AN_GANG("双暗杠", 6) {
        @Override
        public int match(Hupai hupai) {
            int[] data = hupai.getData();
            int n = 0;
            for (int i = 2; data[i] != 0 && i <= 8; i += 2)
                if (isAngang(data[i]))
                    n++;
            if (n == 2)
                return 1;
            return 0;
        }
    },

    /**
     * 双箭刻(6)<br/>
     * <br/>
     * 两副箭刻
     */
    SHUANG_JIAN_KE("双箭刻", 6) {
        @Override
        public int match(Hupai hupai) {
            int[] data = hupai.getFullData();
            if (data[50] == 6)
                return 1;
            return 0;
        }
    },

    /**
     * 全带幺(4)<br/>
     * <br/>
     * 和牌时，每副牌、将牌都有幺九字牌
     */
    QUAN_DAI_YAO("全带幺", 4) {
        @Override
        public int match(Hupai hupai) {
            int[] data = hupai.getData();
            if (!Pais.isYaojiuzi(data[45]))
                return 0;
            for (int k = 54; data[k] != 0 && k <= 57; k++)
                if (!Pais.isYaojiuzi(data[k]))
                    return 0;
            for (int s = 46; data[s] != 0 && s <= 49; s++) {
                int p = data[s];
                if (p != 11 && p != 17 && p != 21 && p != 27 && p != 31 && p != 37)
                    return 0;
            }
            return 1;
        }
    },

    /**
     * 不求人(4)<br/>
     * <br/>
     * 四副牌及将中没有吃牌、碰牌、明杠，自摸和牌
     */
    BU_QIU_REN("不求人", 4) {
        @Override
        public int match(Hupai hupai) {
            int[] data = hupai.getData();
            for (int i = 2; data[i] != 0 && i <= 8; i += 2)
                if (!isAngang(data[i]))
                    return 0;
            if (hupai.getType() == HU_ZIJI)
                return 1;
            return 0;
        }
    },

    /**
     * 双明杠(4)<br/>
     * <br/>
     * 两个明杠
     */
    SHUANG_MING_GANG("双明杠", 4) {
        @Override
        public int match(Hupai hupai) {
            int[] data = hupai.getData();
            int n = 0;
            for (int i = 2; data[i] != 0 && i <= 8; i += 2)
                if (isMinggang(data[i]))
                    n++;
            if (n == 2)
                return 1;
            return 0;
        }
    },

    /**
     * 和绝张(4)<br/>
     * <br/>
     * 和牌池、桌面已亮明的三张牌所剩的第四张牌
     */
    HU_JUE_ZHANG("和绝张", 4) {
        @Override
        public int match(Hupai hupai) {
            return hupai.isJuezhang() ? 1 : 0;
        }
    },

    /**
     * 箭刻(2)<br/>
     * <br/>
     * 中发白的刻
     */
    /*
     * 因为有三元及双箭刻，所以此牌型最多只有一个
     */
    JIAN_KE("箭刻", 2) {
        @Override
        public int match(Hupai hupai) {
            int[] data = hupai.getFullData();
            if (data[50] == 3 || data[50] == 5)
                return 1;
            return 0;
        }
    },

    /**
     * 圈风刻(2)<br/>
     * <br/>
     * 与圈风相同的风刻
     */
    QUAN_FENG_KE("圈风刻", 2) {
        @Override
        public int match(Hupai hupai) {
            int[] data = hupai.getData();
            int quanfeng = hupai.getQuanfeng();
            for (int i = 54; data[i] != 0 && i <= 57; i++)
                if (data[i] == quanfeng)
                    return 1;
            return 0;
        }
    },

    /**
     * 门风刻(2)<br/>
     * <br/>
     * 与本门风相同的风刻
     */
    MEN_FENG_KE("门风刻", 2) {
        @Override
        public int match(Hupai hupai) {
            int[] data = hupai.getData();
            int menfeng = hupai.getMenfeng();
            for (int i = 54; data[i] != 0 && i <= 57; i++)
                if (data[i] == menfeng)
                    return 1;
            return 0;
        }
    },

    /**
     * 门前清(2)<br/>
     * <br/>
     * 没有吃、碰、明杠，和别人打出的牌
     */
    MEN_QIAN_QING("门前清", 2) {
        @Override
        public int match(Hupai hupai) {
            int[] data = hupai.getData();
            for (int i = 2; data[i] != 0 && i <= 8; i += 2)
                if (!isAngang(data[i]))
                    return 0;
            if (hupai.getType() != HU_ZIJI)
                return 1;
            return 0;
        }
    },

    /**
     * 平和(2)<br/>
     * <br/>
     * 由四副顺及序数牌作将组成的和牌，边、坎、钓不影响平和
     */
    PING_HU("平和", 2) {
        @Override
        public int match(Hupai hupai) {
            int[] data = hupai.getData();
            if (data[49] != 0 && data[45] <= 39)
                return 1;
            return 0;
        }
    },

    /**
     * 四归一(2)<br/>
     * <br/>
     * 和牌中，有四张相同的牌(不包括杠牌)
     */
    SI_GUI_YI("四归一", 2) {
        @Override
        public int match(Hupai hupai) {
            int[] data = hupai.getFullData();
            int n = 0;
            int p = 11;
            if (data[10] >= 4)
                for (; p <= 19; p++)
                    if (data[p] == 4)
                        n++;
            if (data[20] >= 4)
                for (p = 21; p <= 29; p++)
                    if (data[p] == 4)
                        n++;
            if (data[30] >= 4)
                for (p = 31; p <= 39; p++)
                    if (data[p] == 4)
                        n++;
            if (data[40] >= 4)
                for (p = 41; p <= 44; p++)
                    if (data[p] == 4)
                        n++;
            if (data[50] >= 4)
                for (p = 51; p <= 53; p++)
                    if (data[p] == 4)
                        n++;
            return n;
        }
    },

    /**
     * 双同刻(2)<br/>
     * <br/>
     * 两副序数相同的刻
     */
    /*
     * 最多两个
     */
    SHUANG_TONG_KE("双同刻", 2) {
        @Override
        public int match(Hupai hupai) {
            int[] data = hupai.getData();
            int k2 = data[55];
            if (k2 == 0 || k2 > 39) // 两刻
                return 0;
            int k1 = data[54];
            int k3 = data[56];
            int k11 = k1 + 10;
            int k12 = k1 + 20;
            if (k3 == 0 || k3 > 39) {
                if (k2 == k11 || k2 == k12) // 111m 111n 0 0
                    return 1;
                return 0;
            }
            int k4 = data[57];
            int k21 = k2 + 10;
            int k22 = k2 + 20;
            if (k4 == 0 || k4 > 39) {
                if (k2 == k11 || k2 == k12 //111m 111n xxxx 0
                 || k3 == k11 || k3 == k12 //111m xxxx 111n 0
                 || k3 == k21 || k3 == k22)//xxxx 111m 111n 0
                    return 1;
                return 0;
            }
            int k31 = k3 + 10;
            if (k3 == k11 && (k4 == k22  // 111w 222w 111t 222b
                           || k4 == k21) // 111w 222w 111t 222t 或 111t 222t 111b 222b
             || k2 == k11 && k4 == k31   // 111w 111t 222t 222b
             || k3 == k12 && (k4 == k21  // 111w 222t 111b 222b
                           || k4 == k22))// 111w 222w 111b 222b
                return 2;
            int k32 = k3 + 20;
            if (k2 == k11 || k2 == k12 // 111m 111n xxxx xxxx
             || k3 == k11 || k3 == k12 // 111m xxxx 111n xxxx
             || k4 == k11 || k4 == k12 // 111m xxxx xxxx 111n
             || k3 == k21 || k3 == k22 // xxxx 111m 111n xxxx
             || k4 == k21 || k4 == k22 // xxxx 111m xxxx 111n
             || k4 == k31 || k4 == k32)// xxxx xxxx 111m 111n
                return 1;
            return 0;
        }
    },

    /**
     * 双暗刻(2)<br/>
     * <br/>
     * 两个暗刻
     */
    SHUANG_AN_KE("双暗刻", 2) {
        @Override
        public int match(Hupai hupai) {
            int[] data = hupai.getData();
            if (data[55] == 0) // 两刻
                return 0;
            int gp = 0;
            for (int i = 2; data[i] != 0 && i <= 8; i += 2)
                if (isPeng(data[i]) || isMinggang(data[i]))
                    gp++;
            int k3 = data[56];
            int k4 = data[57];
            if (k3 == 0 && gp == 0 
             || k3 != 0 && (k4 == 0 && gp == 1
                         || k4 != 0 && gp == 2)) {
                 int p = hupai.getPaihao();
                if (p == data[45] // 和将
                 || hupai.getType() == HU_ZIJI // 自摸
                 || data[54] != p && data[55] != p && data[56] != p && data[57] != p // 不是和的刻牌
                 || data[p] == 4) // 和的刻牌，但是是 33345和3，算一暗刻
                return 1;
            }
            return 0;
        }
    },

    /**
     * 暗杠(2)<br/>
     * <br/>
     * 自抓四张相同的牌开杠
     */
    /*
     * 四杠、三杠、双暗杠都判断过，所以此牌型只能返回1
     */
    AN_GANG("暗杠", 2) {
        @Override
        public int match(Hupai hupai) {
            int[] data = hupai.getData();
            for (int i = 2; data[i] != 0 && i <= 8; i += 2)
                if (isAngang(data[i]))
                    return 1;
            return 0;
        }
    },

    /**
     * 断幺九(2)<br/>
     * <br/>
     * 和牌中没有19及字牌
     */
    DUAN_YAO_JIU("断幺九", 2) {
        @Override
        public int match(Hupai hupai) {
            int[] data = hupai.getFullData();
            for (int p : YAO_JIU_ZI)
                if (data[p] != 0)
                    return 0;
            return 1;
        }
    },

    /*
     * 一般高、喜相逢、连六、老少副四种牌型，很容易出现互相包含的情况，国标中并没有明确的说明，下面的匹配是作者自己理解的一种比较合理的方式。
     */

    /**
     * 一般高(1)<br/>
     * <br/>
     * 一种花色两副相同的顺
     */
    /*
     * 最多有两个(不同花色)
     * 同一花色的话已经判断过一色四同顺和一色三同顺
     */
    YI_BAN_GAO("一般高", 1) {
        @Override
        public int match(Hupai hupai) {
            int[] data = hupai.getData();
            int s2 = data[47];
            if (s2 == 0) // 两顺
                return 0;
            int s1 = data[46];
            int s3 = data[48];
            if (s3 == 0) {
                if (s1 == s2) // 123m 123n 0 0
                    return 1;
                return 0;
            }
            int s4 = data[49];
            if (s4 == 0) {
                if (s1 == s2  // 123m 123n xxxx 0
                 || s2 == s3) // xxxx 123m 123n 0
                    return 1;
                return 0;
            }
            if (s1 == s2 && s3 == s4) // 123m 123m 456n 456n
                return 2;
            if (s1 == s2 // 123m 123n xxxx xxxx
             || s2 == s3 // xxxx 123m 123n xxxx
             || s3 == s4)// xxxx xxxx 123m 123n
                return 1;
            return 0;
        }
    },

    /**
     * 喜相逢(1)<br/>
     * <br/>
     * 两种花色两副序数相同的顺
     */
    /*
     * 最多有两个，123w 123w 123t只能算一个，123w 123w 123t 123t算两个
     * 123w 123t 123b算三色三同顺，不算喜相逢
     */
    XI_XIANG_FENG("喜相逢", 1) {
        @Override
        public int match(Hupai hupai) {
            int[] data = hupai.getData();
            int s2 = data[47];
            if (s2 == 0) // 两顺
                return 0;
            int s1 = data[46];
            int s3 = data[48];
            int s110 = s1 + 10;
            int s120 = s1 + 20;
            if (s3 == 0) {
                if (s2 == s110 || s2 == s120) // 123m 123n 0 0
                    return 1;
                return 0;
            }
            int s4 = data[49];
            int s210 = s2 + 10;
            int s220 = s2 + 20;
            if (s4 == 0) {
                if (s2 == s110 || s2 == s120 // 123m 123n xxxx 0
                 || s3 == s110 || s3 == s120 // 123m xxxx 123n 0
                 || s3 == s210 || s3 == s220)// xxxx 123m 123n 0
                    return 1;
                return 0;
            }
            int s310 = s3 + 10;
            if (s3 == s110 && (s4 == s220  // 123w 456w 123t 456b
                            || s4 == s210) // 123w 456w 123t 456t 或 123t 456t 123b 456b
             || s2 == s110 && s4 == s310   // 123w 123t 456t 456b
             || s3 == s120 && (s4 == s210  // 123w 456t 123b 456b
                            || s4 == s220))// 123w 456w 123b 456b
                return 2;
            int s320 = s3 + 20;
            if (s2 == s110 || s2 == s120 // 123m 123n xxxx xxxx
             || s3 == s110 || s3 == s120 // 123m xxxx 123n xxxx
             || s4 == s110 || s4 == s120 // 123m xxxx xxxx 123n
             || s3 == s210 || s3 == s220 // xxxx 123m 123n xxxx
             || s4 == s210 || s4 == s220 // xxxx 123m xxxx 123n
             || s4 == s310 || s4 == s320)// xxxx xxxx 123m 123n
                return 1;
            return 0;
        }
    },

    /**
     * 连六(1)<br/>
     * <br/>
     * 一种花色六张相连接的序数牌组成两幅顺
     */
    /*
     * 最多有两个
     * 同一种花色123 456 456或者123 123 456只能算一个，但123 123 456 456算两个
     * 不同花色可有两个，如123w 456w 345t 678t
     * 另外123 456 789算清龙
     */
    LIAN_LIU("连六", 1) {
        @Override
        public int match(Hupai hupai) {
            int[] data = hupai.getData();
            int s2 = data[47];
            if (s2 == 0) // 两顺
                return 0;
            int s1 = data[46];
            int s3 = data[48];
            int s13 = s1 + 3;
            if (s3 == 0) {
                if (s2 == s13) // 123 456 0 0
                    return 1;
                return 0;
            }
            int s4 = data[49];
            int s23 = s2 + 3;
            if (s4 == 0) {
                if (s2 == s13  // 123 456 xxx 0
                 || s3 == s13  // 123 xxx 456 0
                 || s3 == s23) // xxx 123 456 0
                    return 1;
                return 0;
            }
            int s33 = s3 + 3;
            if (s1 == s2 && s3 == s4 && s3 == s13 // 同花色123 123 456 456
             || s2 == s13 && s4 == s33) // 不同花色123 456 123 456
                return 2;
            if (s2 == s13 // 123 456 xxx xxx
             || s3 == s13 // 123 xxx 456 xxx
             || s4 == s13 // 123 xxx xxx 456
             || s3 == s23 // xxx 123 456 xxx
             || s4 == s23 // xxx 123 xxx 456
             || s4 == s33)// xxx xxx 123 456
                return 1;
            return 0;
        }
    },
    
    /**
     * 老少副(1)<br/>
     * <br/>
     * 一种花色牌的123、789两副顺
     */
    /*
     * 最多有两个
     * 同一种花色123 123 789或者123 789 789只能算一个
     * 同花色123 123 789 789或两个花色如123w 789w 123t 789t算两个
     */
    LAO_SHAO_FU("老少副", 1) {
        @Override
        public int match(Hupai hupai) {
            int[] data = hupai.getData();
            int s2 = data[47];
            if (s2 == 0) // 两顺
                return 0;
            int s1 = data[46];
            int s3 = data[48];
            if (s3 == 0) {
                if (s2 == 17 && s1 == 11 // 123w 789w 0 0
                 || s2 == 27 && s1 == 21 // 123t 789t 0 0
                 || s2 == 37 && s1 == 31)// 123b 789b 0 0
                    return 1;
                return 0;
            }
            int s4 = data[49];
            if (s4 == 0) {
                if (s1 == 11 && (s2 == 17  // 123w 789w xxxw 0
                              || s3 == 17) // 123w xxxw 789w 0
                 || s2 == 11 && s3 == 17   // xxxw 123w 789w 0
                 || s1 == 21 && (s2 == 27  // 123t 789t xxxt 0
                              || s3 == 27) // 123t xxxt 789t 0
                 || s2 == 21 && s3 == 27   // xxxx 123t 789t 0
                 || s1 == 31 && (s2 == 37  // 123b xxxb 789b 0
                              || s3 == 37) // 123b 789b xxxb 0
                 || s2 == 31 && s3 == 37)  // xxxx 123b 789b 0
                    return 1;
                return 0;
            }
            if (s1 == 11 && s2 == 11 && s3 == 17 && s4 == 17  // 123w 123w 789w 789w
             || s1 == 21 && s2 == 21 && s3 == 27 && s4 == 27  // 123t 123t 789t 789t
             || s1 == 31 && s2 == 31 && s3 == 37 && s4 == 37  // 123b 123b 789b 789b
             || s1 == 11 && s2 == 17 && (s3 == 21 && s4 == 27 // 123w 789w 123t 789t
                                      || s3 == 31 && s4 == 37)// 123w 789w 123b 789b
             || s1 == 21 && s2 == 27 && s3 == 31 && s4 == 37) // 123t 789t 123b 789b
                return 2;
            if (s1 == 11 || s1 == 21 || s1 == 31) {
                int p = (s1 + 6);
                if (s2 == p // 123 789 xxx xxx
                 || s3 == p // 123 xxx 789 xxx
                 || s4 == p)// 123 xxx xxx 789
                    return 1;
            }
            if (s2 == 11 || s2 == 21 || s2 == 31) {
                int p = (s2 + 6);
                if (s3 == p // xxx 123 789 xxx
                 || s4 == p)// xxx 123 xxx 789
                    return 1;
            }
            if ((s3 == 11 || s3 == 21 || s3 == 31) && s4 == s3 + 6) // xxx xxx 123 789
                return 1;
            return 0;
        }
    },

    /**
     * 幺九刻(1)<br/>
     * <br/>
     * 三张相同的19序数牌及字牌组成的刻
     */
    /*
     * 实际上只能是19的刻和非门风、圈风的风刻
     * 因为箭刻和圈风、门风已有特定牌型判断过
     */
    YAO_JIU_KE("幺九刻", 1) {
        @Override
        public int match(Hupai hupai) {
            int[] data = hupai.getData();
            int quanfeng = hupai.getQuanfeng();
            int menfeng = hupai.getMenfeng();
            int n = 0;
            for (int i = 54; i <= 57; i++) {
                int p = data[i];
                if (p == 0)
                    break;
                if (Pais.isYaojiu(p)
                 || Pais.isFeng(p) && p != quanfeng && p != menfeng)
                    n++;
            }
            return n;
        }
    },

    /**
     * 明杠(1)<br/>
     * <br/>
     * 自己有暗刻，碰别人打出的一张相同的牌开杠，或自己抓进一张与碰的明刻相同的牌开杠
     */
    /*
     * 四杠、三杠、双明杠都判断过，所以此牌型只能返回1
     */
    MING_GANG("明杠", 1) {
        @Override
        public int match(Hupai hupai) {
            int[] data = hupai.getData();
            for (int i = 2; data[i] != 0 && i <= 8; i += 2)
                if (isMinggang(data[i]))
                    return 1;
            return 0;
        }
    },

    /**
     * 缺一门(1)<br/>
     * <br/>
     * 和牌中缺少一种花色序数牌
     */
    /*
     * 万条饼中缺一门，缺字不算
     * 缺两门的话就是混一色或者清一色了
     */
    QUE_YI_MEN("缺一门", 1) {
        @Override
        public int match(Hupai hupai) {
            int[] data = hupai.getFullData();
            if (data[10] == 0 || data[20] == 0 || data[30] == 0)
                return 1;
            return 0;
        }
    },

    /**
     * 无字(1)<br/>
     * <br/>
     * 和牌中没有风、箭牌
     */
    WU_ZI("无字", 1) {
        @Override
        public int match(Hupai hupai) {
            int[] data = hupai.getFullData();
            if (data[40] == 0 && data[50] == 0)
                return 1;
            return 0;
        }
    },

    /**
     * 边张(1)<br/>
     * <br/>
     * 单和123的3及789的7，只听一张时才算
     */
    BIAN_ZHANG("边张", 1) {
        @Override
        public int match(Hupai hupai) {
            int p = hupai.getPaihao();
            if (p != 13 && p != 23 && p != 33 && p != 17 && p != 27 && p != 37)
                return 0;
            int[] data = hupai.getData();
            int s1 = data[46];
            int s2 = data[47];
            int s3 = data[48];
            int s4 = data[49];
            for (int i = 2; data[i] != 0 && i <= 8; i += 2) { // 去掉吃牌的顺
                int type = data[i];
                int s;
                switch (type) {
                    case CHI_LEFT :
                        s = data[i + 1];
                        break;
                    case CHI_CENTER :
                        s = data[i + 1] - 1;
                        break;
                    case CHI_RIGHT :
                        s = data[i + 1] - 2;
                        break;
                    default :
                        continue;
                }
                if (s1 == s)
                    s1 = 0;
                if (s2 == s)
                    s2 = 0;
                if (s3 == s)
                    s3 = 0;
                if (s4 == s)
                    s4 = 0;
            }
            if (p == 13 || p == 23 || p == 33) {
                int s = p - 2;
                if ((s1 == s && s2 != p && s3 != p && s4 != p
                  || s2 == s && s3 != p && s4 != p
                  || s3 == s && s4 != p
                  || s4 == s) // 存在123，不存在345:12345时和3不算
                 && data[54] != p && data[55] != p && data[56] != p && data[57] != p // 不存在333：12333时和3不算
                 && data[45] != s && data[45] != p - 1 // 12不是将：1112、1222时和3不算
                 && data[45] != p) // 3不是将：1233和3不算
                    return 1;
                return 0;
            }
            if (p == 17 || p == 27 || p == 37) {
                int s = p - 2;
                if ((s4 == p && s3 != s && s2 != s && s1 != s
                  || s3 == p && s2 != s && s1 != s
                  || s2 == p && s1 != s
                  || s1 == p) // 存在789，不存在567：56789时和7不算
                 && data[54] != p && data[55] != p && data[56] != p && data[57] != p // 不存在777：77789时和7不算
                 && data[45] != p + 1 && data[45] != p + 2 // 89不是将：8889、8999时和7不算
                 && data[45] != p) // 7不是将：7789和7不算
                    return 1;
                return 0;
            }
            return 0;
        }
    },

    /**
     * 坎张(1)<br/>
     * <br/>
     * 和两张牌之间的牌，只听一张时才算
     */
    KAN_ZHANG("坎张", 1) {
        @Override
        public int match(Hupai hupai) {
            int[] data = hupai.getData();
            int p = hupai.getPaihao();
            if (p == 11 || p == 21 || p == 31
             || p == 19 || p == 29 || p == 39)
                return 0;
            int s1 = data[46];
            int s2 = data[47];
            int s3 = data[48];
            int s4 = data[49];
            int k1 = data[54];
            int k2 = data[55];
            int k3 = data[56];
            int k4 = data[57];
            for (int i = 2; data[i] != 0 && i <= 8; i += 2) { // 去掉吃碰的顺刻
                int type = data[i];
                int s = 0;
                int k = 0;
                switch (type) {
                    case CHI_LEFT :
                        s = data[i + 1];
                        break;
                    case CHI_CENTER :
                        s = data[i + 1] - 1;
                        break;
                    case CHI_RIGHT :
                        s = data[i + 1] - 2;
                        break;
                    case PENG_XIAJIA :
                    case PENG_DUIJIA :
                    case PENG_SHANGJIA :
                        k = data[i + 1];
                        break;
                    default :
                        continue;
                }
                if (s1 == s)
                    s1 = 0;
                if (s2 == s)
                    s2 = 0;
                if (s3 == s)
                    s3 = 0;
                if (s4 == s)
                    s4 = 0;
                if (k1 == k)
                    k1 = 0;
                if (k2 == k)
                    k2 = 0;
                if (k3 == k)
                    k3 = 0;
                if (k4 == k)
                    k4 = 0;
            }
            int s = p - 1;
            int sl = p - 2;
            int p51 = p - 4;
            int p57 = p + 2;
            int sr = p;
            int jiang = data[45];
            if ((s1 == s && s2 != sr && s3 != sr && s4 != sr
              || s2 == s && s1 != sl && s3 != sr && s4 != sr
              || s3 == s && s1 != sl && s2 != sl && s4 != sr
              || s4 == s && s1 != sl && s2 != sl && s3 != sl) // 存在46时和5，不存在345和567：34456、45667时和5不算
             && k1 != p && k2 != p && k3 != p && k4 != p // 不存在555：45556时和5不算
             && jiang != s && jiang != p + 1 // 46不是将：4446、4666时和5不算
             && (p != 15 && p != 25 && p != 35
              || s1 != p51 && s2 != p51 && s3 != p51 && jiang != p51 // 和5时，不是1112346的牌，此情况不算
              || s2 != p57 && s3 != p57 && s4 != p57 && jiang != p + 4)) // 和5时，不是4678999的牌，此情况不算
                return 1;
            return 0;
        }
    },

    /**
     * 单钓将(1)<br/>
     * <br/>
     * 钓单张牌作将成和，只听一张时才算
     */
    DAN_DIAO_JIANG("单钓将", 1) {
        @Override
        public int match(Hupai hupai) {
            int[] data = hupai.getData();
            int p = hupai.getPaihao();
            int s1 = data[46];
            int s2 = data[47];
            int s3 = data[48];
            int s4 = data[49];
            for (int i = 2; data[i] != 0 && i <= 8; i += 2) { // 去掉吃牌的顺
                int type = data[i];
                int s;
                switch (type) {
                    case CHI_LEFT :
                        s = data[i + 1];
                        break;
                    case CHI_CENTER :
                        s = data[i + 1] - 1;
                        break;
                    case CHI_RIGHT :
                        s = data[i + 1] - 2;
                        break;
                    default :
                        continue;
                }
                if (s1 == s)
                    s1 = 0;
                if (s2 == s)
                    s2 = 0;
                if (s3 == s)
                    s3 = 0;
                if (s4 == s)
                    s4 = 0;
            }
            int pp = p % 10;
            int pl = p - 3;
            int pr = p + 1;
            if (data[45]== p // 是将
             && data[p] == 2 // 只有两张
             && (pp == 1 || data[p - 1] != 3) // 5556和6不算
             && (pp == 9 || data[p + 1] != 3) // 5666和5不算
             && (pp == 1 || pp == 2 || pp == 3 || s1 != pl && s2 != pl && s3 != pl && s4 != pl) // 4567和7不算
             && (pp == 7 || pp == 8 || pp == 9 || s1 != pr && s2 != pr && s3 != pr && s4 != pr))// 4567和4不算
                return 1;
            return 0;
        }
    },

    /**
     * 自摸(1)<br/>
     * <br/>
     * 自己抓进牌成和牌
     */
    ZI_MO("自摸", 1) {
        @Override
        public int match(Hupai hupai) {
            return hupai.getType() == HU_ZIJI ? 1 : 0;
        }
    },

    /**
     * 无番和(8)<br/>
     * <br/>
     * 和牌后，数不出任何番种分(花牌不计算在内)
     */
    /*
     * 此牌型比较特殊，必须作为最后一个判断，并且符合别的牌型时都不能再判断此牌型
     * 只要能够进入此牌型，说明没有满足任何其它牌型(除了花牌)，直接返回1
     */
    WU_FAN_HU("无番和", 8) {
        @Override
        public int match(Hupai hupai) {
            return 1;
        }
    },

    /**
     * 花牌(1)<br/>
     * <br/>
     * 即春夏秋冬，梅兰竹菊，每花计一分。不计在起和分内，和牌后才能计分。花牌补花成和计自摸分，不计杠上开花
     */
    HUA_PAI("花牌", 1) {
        @Override
        public int match(Hupai hupai) {
            return hupai.getData()[60];
        }
    };

    /*
     * 初始化满足每种牌型后还需要判断的牌型。这些都是根据规则固定下来的。
     */
    static {
        DA_SI_XI.setNext(
            SI_GANG,                    
            ZI_YI_SE,
            SI_AN_KE,
            SAN_GANG,
            HUN_YAO_JIU,
            SAN_AN_KE,
            MIAO_SHOU_HUI_CHUN,
            HAI_DI_LAO_YUE,
            GANG_SHANG_KAI_HUA,
            HUN_YI_SE,
            QUAN_QIU_REN,
            SHUANG_AN_GANG,
            BU_QIU_REN,
            SHUANG_MING_GANG,
            MEN_QIAN_QING,
            SHUANG_AN_KE,
            AN_GANG,
            MING_GANG,
            DAN_DIAO_JIANG,
            ZI_MO,
            HUA_PAI);
        
        DA_SAN_YUAN.setNext(
            SI_GANG,
            ZI_YI_SE,
            SI_AN_KE,
            SAN_GANG,
            HUN_YAO_JIU,
            SAN_AN_KE,
            MIAO_SHOU_HUI_CHUN,
            HAI_DI_LAO_YUE,
            GANG_SHANG_KAI_HUA,
            QIANG_GANG_HU,
            PENG_PENG_HU,
            HUN_YI_SE,
            QUAN_QIU_REN,
            SHUANG_AN_GANG,
            QUAN_DAI_YAO,
            BU_QIU_REN,
            SHUANG_MING_GANG,
            HU_JUE_ZHANG,
            QUAN_FENG_KE,
            MEN_FENG_KE,
            MEN_QIAN_QING,
            SHUANG_AN_KE,
            AN_GANG,
            YAO_JIU_KE,
            MING_GANG,
            QUE_YI_MEN,
            BIAN_ZHANG,
            KAN_ZHANG,
            DAN_DIAO_JIANG,
            ZI_MO,
            HUA_PAI);
        
        LV_YI_SE.setNext(
            SI_GANG,
            SI_AN_KE,
            YI_SE_SI_TONG_SHUN,
            SAN_GANG,
            QI_DUI,
            QING_YI_SE,
            YI_SE_SAN_JIE_GAO,
            YI_SE_SAN_TONG_SHUN,
            SAN_AN_KE,
            MIAO_SHOU_HUI_CHUN,
            HAI_DI_LAO_YUE,
            GANG_SHANG_KAI_HUA,
            QIANG_GANG_HU,
            PENG_PENG_HU,
            QUAN_QIU_REN,
            SHUANG_AN_GANG,
            BU_QIU_REN,
            SHUANG_MING_GANG,
            HU_JUE_ZHANG,
            JIAN_KE,
            MEN_QIAN_QING,
            PING_HU,
            SI_GUI_YI,
            SHUANG_AN_KE,
            AN_GANG,
            DUAN_YAO_JIU,
            YI_BAN_GAO,
            MING_GANG,
            KAN_ZHANG,
            DAN_DIAO_JIANG,
            ZI_MO,
            HUA_PAI);
        
        JIU_LIAN_BAO_DENG.setNext(
            QING_LONG,
            MIAO_SHOU_HUI_CHUN,
            HAI_DI_LAO_YUE,
            SI_GUI_YI,
            LIAN_LIU,
            ZI_MO,
            HUA_PAI);
        
        SI_GANG.setNext(
            QING_YAO_JIU,
            XIAO_SI_XI,
            XIAO_SAN_YUAN,
            ZI_YI_SE,
            SI_AN_KE,
            YI_SE_SI_JIE_GAO,
            HUN_YAO_JIU,
            QUAN_SHUANG_KE,
            QING_YI_SE,
            YI_SE_SAN_JIE_GAO,
            QUAN_DA,
            QUAN_ZHONG,
            QUAN_XIAO,
            SAN_TONG_KE,
            SAN_AN_KE,
            DA_YU_WU,
            XIAO_YU_WU,
            SAN_FENG_KE,
            TUI_BU_DAO,
            SAN_SE_SAN_JIE_GAO,
            MIAO_SHOU_HUI_CHUN,
            HAI_DI_LAO_YUE,
            GANG_SHANG_KAI_HUA,
            HUN_YI_SE,
            WU_MEN_QI,
            QUAN_QIU_REN,
            SHUANG_JIAN_KE,
            BU_QIU_REN,
            JIAN_KE,
            QUAN_FENG_KE,
            MEN_FENG_KE,
            MEN_QIAN_QING,
            SHUANG_TONG_KE,
            SHUANG_AN_KE,
            DUAN_YAO_JIU,
            YAO_JIU_KE,
            QUE_YI_MEN,
            WU_ZI,
            DAN_DIAO_JIANG,
            ZI_MO,
            HUA_PAI);
        
        LIAN_QI_DUI.setNext(
            MIAO_SHOU_HUI_CHUN,
            HAI_DI_LAO_YUE,
            DUAN_YAO_JIU,
            ZI_MO,
            HUA_PAI);
        
        SHI_SAN_YAO.setNext(
            MIAO_SHOU_HUI_CHUN,
            HAI_DI_LAO_YUE,
            QIANG_GANG_HU,
            HU_JUE_ZHANG,
            ZI_MO,
            HUA_PAI);
        
        QING_YAO_JIU.setNext(
            SI_AN_KE,
            SAN_GANG,
            QI_DUI,
            SAN_AN_KE,
            MIAO_SHOU_HUI_CHUN,
            HAI_DI_LAO_YUE,
            GANG_SHANG_KAI_HUA,
            QUAN_QIU_REN,
            SHUANG_AN_GANG,
            BU_QIU_REN,
            SHUANG_MING_GANG,
            SI_GUI_YI, // 七对时
            SHUANG_AN_KE,
            AN_GANG,
            MING_GANG,
            QUE_YI_MEN, // 七对时
            DAN_DIAO_JIANG,
            ZI_MO,
            HUA_PAI);
        
        XIAO_SI_XI.setNext(
            ZI_YI_SE,
            SI_AN_KE,
            SAN_GANG,
            HUN_YAO_JIU,
            SAN_AN_KE,
            MIAO_SHOU_HUI_CHUN,
            HAI_DI_LAO_YUE,
            GANG_SHANG_KAI_HUA,
            QIANG_GANG_HU,
            PENG_PENG_HU,
            HUN_YI_SE,
            QUAN_QIU_REN,
            SHUANG_AN_GANG,
            QUAN_DAI_YAO,
            BU_QIU_REN,
            SHUANG_MING_GANG,
            HU_JUE_ZHANG,
            JIAN_KE,
            QUAN_FENG_KE,
            MEN_FENG_KE,
            MEN_QIAN_QING,
            SHUANG_AN_KE,
            AN_GANG,
            YAO_JIU_KE, //TODO 应该不计风的幺九刻，只记19的
            MING_GANG,
            BIAN_ZHANG,
            KAN_ZHANG,
            DAN_DIAO_JIANG,
            ZI_MO,
            HUA_PAI);
        
        XIAO_SAN_YUAN.setNext(
            ZI_YI_SE,
            SI_AN_KE,
            SAN_GANG,
            HUN_YAO_JIU,
            SAN_AN_KE,
            MIAO_SHOU_HUI_CHUN,
            HAI_DI_LAO_YUE,
            GANG_SHANG_KAI_HUA,
            QIANG_GANG_HU,
            PENG_PENG_HU,
            HUN_YI_SE,
            QUAN_QIU_REN,
            SHUANG_AN_GANG,
            QUAN_DAI_YAO,
            BU_QIU_REN,
            SHUANG_MING_GANG,
            HU_JUE_ZHANG,
            QUAN_FENG_KE,
            MEN_FENG_KE,
            MEN_QIAN_QING,
            SI_GUI_YI,
            SHUANG_TONG_KE,
            SHUANG_AN_KE,
            AN_GANG,
            YI_BAN_GAO,
            XI_XIANG_FENG,
            LIAN_LIU,
            LAO_SHAO_FU,
            YAO_JIU_KE,//TODO 应该不计箭的幺九刻，只记19的
            MING_GANG,
            QUE_YI_MEN,
            BIAN_ZHANG,
            KAN_ZHANG,
            DAN_DIAO_JIANG,
            ZI_MO,
            HUA_PAI);
        
        ZI_YI_SE.setNext(
            SI_AN_KE,
            SAN_GANG,
            QI_DUI,
            SAN_AN_KE,
            SAN_FENG_KE,
            MIAO_SHOU_HUI_CHUN,
            HAI_DI_LAO_YUE,
            GANG_SHANG_KAI_HUA,
            QUAN_QIU_REN,
            SHUANG_AN_GANG,
            SHUANG_JIAN_KE,
            BU_QIU_REN,
            SHUANG_MING_GANG,
            JIAN_KE,
            QUAN_FENG_KE,
            MEN_FENG_KE,
            MEN_QIAN_QING,
            SHUANG_AN_KE,
            AN_GANG,
            YAO_JIU_KE,
            MING_GANG,
            DAN_DIAO_JIANG,
            ZI_MO,
            HUA_PAI);
        
        SI_AN_KE.setNext(
            YI_SE_SI_JIE_GAO,
            SAN_GANG,
            HUN_YAO_JIU,
            QUAN_SHUANG_KE,
            QING_YI_SE,
            YI_SE_SAN_JIE_GAO,
            QUAN_DA,
            QUAN_ZHONG,
            QUAN_XIAO,
            SAN_TONG_KE,
            DA_YU_WU,
            XIAO_YU_WU,
            SAN_FENG_KE,
            TUI_BU_DAO,
            SAN_SE_SAN_JIE_GAO,
            MIAO_SHOU_HUI_CHUN,
            HAI_DI_LAO_YUE,
            GANG_SHANG_KAI_HUA,
            HUN_YI_SE,
            WU_MEN_QI,
            SHUANG_AN_GANG,
            SHUANG_JIAN_KE,
            BU_QIU_REN,
            JIAN_KE,
            QUAN_FENG_KE,
            MEN_FENG_KE,
            SHUANG_TONG_KE,
            AN_GANG,
            DUAN_YAO_JIU,
            YAO_JIU_KE,
            QUE_YI_MEN,
            WU_ZI,
            DAN_DIAO_JIANG,
            ZI_MO,
            HUA_PAI);
        
        YI_SE_SHUANG_LONG_HUI.setNext(
            MIAO_SHOU_HUI_CHUN,
            HAI_DI_LAO_YUE,
            QUAN_QIU_REN,
            BU_QIU_REN,
            HU_JUE_ZHANG,
            MEN_QIAN_QING,
            BIAN_ZHANG,
            KAN_ZHANG,
            DAN_DIAO_JIANG,
            ZI_MO,
            HUA_PAI);
        
        YI_SE_SI_JIE_GAO.setNext(
            SAN_GANG,
            QING_YI_SE,
            SAN_AN_KE,
            DA_YU_WU,
            XIAO_YU_WU,
            TUI_BU_DAO,
            MIAO_SHOU_HUI_CHUN,
            HAI_DI_LAO_YUE,
            GANG_SHANG_KAI_HUA,
            HUN_YI_SE,
            QUAN_QIU_REN,
            SHUANG_AN_GANG,
            BU_QIU_REN,
            SHUANG_MING_GANG,
            MEN_QIAN_QING,
            SHUANG_AN_KE,
            AN_GANG,
            DUAN_YAO_JIU,
            YAO_JIU_KE,
            MING_GANG,
            QUE_YI_MEN,
            WU_ZI,
            DAN_DIAO_JIANG,
            ZI_MO,
            HUA_PAI);
        
        YI_SE_SI_TONG_SHUN.setNext(
            QING_YI_SE,
            QUAN_DA,
            QUAN_ZHONG,
            QUAN_XIAO,
            QUAN_DAI_WU,
            DA_YU_WU,
            XIAO_YU_WU,
            TUI_BU_DAO,
            MIAO_SHOU_HUI_CHUN,
            HAI_DI_LAO_YUE,
            HUN_YI_SE,
            QUAN_QIU_REN,
            QUAN_DAI_YAO,
            BU_QIU_REN,
            HU_JUE_ZHANG,
            MEN_QIAN_QING,
            PING_HU,
            DUAN_YAO_JIU,
            QUE_YI_MEN,
            WU_ZI,
            BIAN_ZHANG,
            KAN_ZHANG,
            DAN_DIAO_JIANG,
            ZI_MO,
            HUA_PAI);
        
        YI_SE_SI_BU_GAO.setNext(
            QING_YI_SE,
            MIAO_SHOU_HUI_CHUN,
            HAI_DI_LAO_YUE,
            QIANG_GANG_HU,
            HUN_YI_SE,
            QUAN_QIU_REN,
            BU_QIU_REN,
            HU_JUE_ZHANG,
            MEN_QIAN_QING,
            PING_HU,
            SI_GUI_YI,
            DUAN_YAO_JIU,
            QUE_YI_MEN,
            WU_ZI,
            DAN_DIAO_JIANG,
            ZI_MO,
            HUA_PAI);
        
        SAN_GANG.setNext(
            HUN_YAO_JIU,
            QUAN_SHUANG_KE,
            QING_YI_SE,
            YI_SE_SAN_JIE_GAO,
            QUAN_DA,
            QUAN_ZHONG,
            QUAN_XIAO,
            SAN_TONG_KE,
            SAN_AN_KE,
            DA_YU_WU,
            XIAO_YU_WU,
            SAN_FENG_KE,
            TUI_BU_DAO,
            SAN_SE_SAN_JIE_GAO,
            MIAO_SHOU_HUI_CHUN,
            HAI_DI_LAO_YUE,
            GANG_SHANG_KAI_HUA,
            QIANG_GANG_HU,
            PENG_PENG_HU,
            HUN_YI_SE,
            WU_MEN_QI,
            QUAN_QIU_REN,
            SHUANG_JIAN_KE,
            QUAN_DAI_YAO,
            BU_QIU_REN,
            HU_JUE_ZHANG,
            JIAN_KE,
            QUAN_FENG_KE,
            MEN_FENG_KE,
            MEN_QIAN_QING,
            SHUANG_TONG_KE,
            SHUANG_AN_KE,
            DUAN_YAO_JIU,
            YAO_JIU_KE,
            QUE_YI_MEN,
            WU_ZI,
            BIAN_ZHANG,
            KAN_ZHANG,
            DAN_DIAO_JIANG,
            ZI_MO,
            HUA_PAI);
        
        HUN_YAO_JIU.setNext( // TODO 没算幺九刻
            QI_DUI,
            SAN_TONG_KE,
            SAN_AN_KE,
            SAN_FENG_KE,
            MIAO_SHOU_HUI_CHUN,
            HAI_DI_LAO_YUE,
            GANG_SHANG_KAI_HUA,
            HUN_YI_SE,
            WU_MEN_QI,
            QUAN_QIU_REN,
            SHUANG_AN_GANG,
            SHUANG_JIAN_KE,
            BU_QIU_REN,
            SHUANG_MING_GANG,
            JIAN_KE,
            QUAN_FENG_KE,
            MEN_FENG_KE,
            MEN_QIAN_QING,
            SHUANG_TONG_KE,
            SHUANG_AN_KE,
            AN_GANG,
            MING_GANG,
            QUE_YI_MEN,
            DAN_DIAO_JIANG,
            ZI_MO,
            HUA_PAI);
        
        QI_DUI.setNext(
            QING_YI_SE,
            QUAN_DA,
            QUAN_ZHONG,
            QUAN_XIAO,
            DA_YU_WU,
            XIAO_YU_WU,
            TUI_BU_DAO,
            MIAO_SHOU_HUI_CHUN,
            HAI_DI_LAO_YUE,
            HUN_YI_SE,
            WU_MEN_QI,
            SI_GUI_YI,
            DUAN_YAO_JIU,
            QUE_YI_MEN,
            WU_ZI,
            ZI_MO,
            HUA_PAI);
        
        QI_XING_BU_KAO.setNext(
            MIAO_SHOU_HUI_CHUN,
            HAI_DI_LAO_YUE,
            QIANG_GANG_HU,
            HU_JUE_ZHANG,
            ZI_MO,
            HUA_PAI);
        
        QUAN_SHUANG_KE.setNext(
            QUAN_ZHONG,
            SAN_TONG_KE,
            SAN_AN_KE,
            DA_YU_WU,
            XIAO_YU_WU,
            TUI_BU_DAO,
            MIAO_SHOU_HUI_CHUN,
            HAI_DI_LAO_YUE,
            GANG_SHANG_KAI_HUA,
            QUAN_QIU_REN,
            SHUANG_AN_GANG,
            BU_QIU_REN,
            SHUANG_MING_GANG,
            MEN_QIAN_QING,
            SHUANG_TONG_KE,
            SHUANG_AN_KE,
            AN_GANG,
            MING_GANG,
            QUE_YI_MEN,
            DAN_DIAO_JIANG,
            ZI_MO,
            HUA_PAI);
        
        QING_YI_SE.setNext(
            YI_SE_SAN_JIE_GAO,
            YI_SE_SAN_TONG_SHUN,
            QING_LONG,
            YI_SE_SAN_BU_GAO,
            SAN_AN_KE,
            DA_YU_WU,
            XIAO_YU_WU,
            TUI_BU_DAO,
            MIAO_SHOU_HUI_CHUN,
            HAI_DI_LAO_YUE,
            GANG_SHANG_KAI_HUA,
            QIANG_GANG_HU,
            PENG_PENG_HU,
            QUAN_QIU_REN,
            SHUANG_AN_GANG,
            QUAN_DAI_YAO,
            BU_QIU_REN,
            SHUANG_MING_GANG,
            HU_JUE_ZHANG,
            MEN_QIAN_QING,
            PING_HU,
            SI_GUI_YI,
            SHUANG_AN_KE,
            AN_GANG,
            DUAN_YAO_JIU,
            YI_BAN_GAO,
            XI_XIANG_FENG,
            LIAN_LIU,
            LAO_SHAO_FU,
            YAO_JIU_KE,
            MING_GANG,
            BIAN_ZHANG,
            KAN_ZHANG,
            DAN_DIAO_JIANG,
            ZI_MO,
            HUA_PAI);
        
        YI_SE_SAN_JIE_GAO.setNext(
            QUAN_DA,
            QUAN_ZHONG,
            QUAN_XIAO,
            SAN_AN_KE,
            DA_YU_WU,
            XIAO_YU_WU,
            TUI_BU_DAO,
            MIAO_SHOU_HUI_CHUN,
            HAI_DI_LAO_YUE,
            GANG_SHANG_KAI_HUA,
            QIANG_GANG_HU,
            PENG_PENG_HU,
            HUN_YI_SE,
            QUAN_QIU_REN,
            SHUANG_AN_GANG,
            BU_QIU_REN,
            SHUANG_MING_GANG,
            HU_JUE_ZHANG,
            JIAN_KE,
            QUAN_FENG_KE,
            MEN_FENG_KE,
            MEN_QIAN_QING,
            SI_GUI_YI,
            SHUANG_TONG_KE,
            SHUANG_AN_KE,
            AN_GANG,
            DUAN_YAO_JIU,
            YAO_JIU_KE,
            MING_GANG,
            QUE_YI_MEN,
            WU_ZI,
            BIAN_ZHANG,
            KAN_ZHANG,
            DAN_DIAO_JIANG,
            ZI_MO,
            HUA_PAI);
        
        YI_SE_SAN_TONG_SHUN.setNext(
            QUAN_DA,
            QUAN_ZHONG,
            QUAN_XIAO,
            QUAN_DAI_WU,
            DA_YU_WU,
            XIAO_YU_WU,
            TUI_BU_DAO,
            MIAO_SHOU_HUI_CHUN,
            HAI_DI_LAO_YUE,
            GANG_SHANG_KAI_HUA,
            QIANG_GANG_HU,
            HUN_YI_SE,
            QUAN_QIU_REN,
            QUAN_DAI_YAO,
            BU_QIU_REN,
            HU_JUE_ZHANG,
            JIAN_KE,
            QUAN_FENG_KE,
            MEN_FENG_KE,
            MEN_QIAN_QING,
            PING_HU,
            SI_GUI_YI,
            AN_GANG,
            DUAN_YAO_JIU,
            XI_XIANG_FENG,
            LIAN_LIU,
            LAO_SHAO_FU,
            YAO_JIU_KE,
            MING_GANG,
            QUE_YI_MEN,
            WU_ZI,
            BIAN_ZHANG,
            KAN_ZHANG,
            DAN_DIAO_JIANG,
            ZI_MO,
            HUA_PAI);
        
        QUAN_DA.setNext(
            SAN_TONG_KE,
            SAN_AN_KE,
            TUI_BU_DAO, // 七对时
            SAN_SE_SAN_JIE_GAO,
            SAN_SE_SAN_TONG_SHUN,
            MIAO_SHOU_HUI_CHUN,
            HAI_DI_LAO_YUE,
            GANG_SHANG_KAI_HUA,
            QIANG_GANG_HU,
            PENG_PENG_HU,
            QUAN_QIU_REN,
            SHUANG_AN_GANG,
            QUAN_DAI_YAO,
            BU_QIU_REN,
            SHUANG_MING_GANG,
            HU_JUE_ZHANG,
            MEN_QIAN_QING,
            PING_HU,
            SI_GUI_YI,
            SHUANG_TONG_KE,
            SHUANG_AN_KE,
            AN_GANG,
            DUAN_YAO_JIU,
            YI_BAN_GAO,
            XI_XIANG_FENG,
            YAO_JIU_KE,
            MING_GANG,
            QUE_YI_MEN,
            BIAN_ZHANG,
            KAN_ZHANG,
            DAN_DIAO_JIANG,
            ZI_MO,
            HUA_PAI);
        
        QUAN_ZHONG.setNext(
            QUAN_DAI_WU,
            SAN_TONG_KE,
            SAN_AN_KE,
            TUI_BU_DAO,
            SAN_SE_SAN_JIE_GAO,
            SAN_SE_SAN_TONG_SHUN,
            MIAO_SHOU_HUI_CHUN,
            HAI_DI_LAO_YUE,
            GANG_SHANG_KAI_HUA,
            QIANG_GANG_HU,
            PENG_PENG_HU,
            QUAN_QIU_REN,
            SHUANG_AN_GANG,
            BU_QIU_REN,
            SHUANG_MING_GANG,
            HU_JUE_ZHANG,
            MEN_QIAN_QING,
            PING_HU,
            SI_GUI_YI,
            SHUANG_TONG_KE,
            SHUANG_AN_KE,
            AN_GANG,
            YI_BAN_GAO,
            XI_XIANG_FENG,
            MING_GANG,
            QUE_YI_MEN,
            KAN_ZHANG,
            DAN_DIAO_JIANG,
            ZI_MO,
            HUA_PAI);
        
        QUAN_XIAO.setNext(
            SAN_TONG_KE,
            SAN_AN_KE,
            TUI_BU_DAO, // 七对时
            SAN_SE_SAN_JIE_GAO,
            SAN_SE_SAN_TONG_SHUN,
            MIAO_SHOU_HUI_CHUN,
            HAI_DI_LAO_YUE,
            GANG_SHANG_KAI_HUA,
            QIANG_GANG_HU,
            PENG_PENG_HU,
            QUAN_QIU_REN,
            SHUANG_AN_GANG,
            QUAN_DAI_YAO,
            BU_QIU_REN,
            SHUANG_MING_GANG,
            HU_JUE_ZHANG,
            MEN_QIAN_QING,
            PING_HU,
            SI_GUI_YI,
            SHUANG_TONG_KE,
            SHUANG_AN_KE,
            AN_GANG,
            DUAN_YAO_JIU,
            YI_BAN_GAO,
            XI_XIANG_FENG,
            YAO_JIU_KE,
            MING_GANG,
            QUE_YI_MEN,
            BIAN_ZHANG,
            KAN_ZHANG,
            DAN_DIAO_JIANG,
            ZI_MO,
            HUA_PAI);
        
        QING_LONG.setNext(
            MIAO_SHOU_HUI_CHUN,
            HAI_DI_LAO_YUE,
            GANG_SHANG_KAI_HUA,
            QIANG_GANG_HU,
            HUN_YI_SE,
            QUAN_QIU_REN,
            BU_QIU_REN,
            HU_JUE_ZHANG,
            JIAN_KE,
            QUAN_FENG_KE,
            MEN_FENG_KE,
            MEN_QIAN_QING,
            PING_HU,
            SI_GUI_YI,
            AN_GANG,
            YI_BAN_GAO,
            XI_XIANG_FENG,
            YAO_JIU_KE,
            MING_GANG,
            QUE_YI_MEN,
            WU_ZI,
            BIAN_ZHANG,
            KAN_ZHANG,
            DAN_DIAO_JIANG,
            ZI_MO,
            HUA_PAI);
        
        SAN_SE_SHUANG_LONG_HUI.setNext(
            MIAO_SHOU_HUI_CHUN,
            HAI_DI_LAO_YUE,
            QUAN_QIU_REN,
            BU_QIU_REN,
            HU_JUE_ZHANG,
            MEN_QIAN_QING,
            BIAN_ZHANG,
            KAN_ZHANG,
            DAN_DIAO_JIANG,
            ZI_MO,
            HUA_PAI);
        
        YI_SE_SAN_BU_GAO.setNext(
            QUAN_DAI_WU,
            TUI_BU_DAO,
            MIAO_SHOU_HUI_CHUN,
            HAI_DI_LAO_YUE,
            GANG_SHANG_KAI_HUA,
            QIANG_GANG_HU,
            HUN_YI_SE,
            QUAN_QIU_REN,
            BU_QIU_REN,
            HU_JUE_ZHANG,
            JIAN_KE,
            QUAN_FENG_KE,
            MEN_FENG_KE,
            MEN_QIAN_QING,
            PING_HU,
            SI_GUI_YI,
            AN_GANG,
            DUAN_YAO_JIU,
            YI_BAN_GAO,
            XI_XIANG_FENG,
            LIAN_LIU,
            LAO_SHAO_FU,
            YAO_JIU_KE,
            MING_GANG,
            QUE_YI_MEN,
            WU_ZI,
            BIAN_ZHANG,
            KAN_ZHANG,
            DAN_DIAO_JIANG,
            ZI_MO,
            HUA_PAI);
        
        QUAN_DAI_WU.setNext(
            TUI_BU_DAO,
            SAN_SE_SAN_TONG_SHUN,
            MIAO_SHOU_HUI_CHUN,
            HAI_DI_LAO_YUE,
            GANG_SHANG_KAI_HUA,
            QIANG_GANG_HU,
            SAN_SE_SAN_BU_GAO,
            QUAN_QIU_REN,
            SHUANG_AN_GANG,
            BU_QIU_REN,
            SHUANG_MING_GANG,
            HU_JUE_ZHANG,
            MEN_QIAN_QING,
            PING_HU,
            SI_GUI_YI,
            SHUANG_TONG_KE,
            SHUANG_AN_KE,
            AN_GANG,
            YI_BAN_GAO,
            XI_XIANG_FENG,
            MING_GANG,
            QUE_YI_MEN,
            KAN_ZHANG,
            DAN_DIAO_JIANG,
            ZI_MO,
            HUA_PAI);
        
        SAN_TONG_KE.setNext(
            SAN_AN_KE,
            DA_YU_WU,
            XIAO_YU_WU,
            MIAO_SHOU_HUI_CHUN,
            HAI_DI_LAO_YUE,
            GANG_SHANG_KAI_HUA,
            QIANG_GANG_HU,
            PENG_PENG_HU,
            WU_MEN_QI,
            QUAN_QIU_REN,
            SHUANG_AN_GANG,
            QUAN_DAI_YAO,
            BU_QIU_REN,
            SHUANG_MING_GANG,
            HU_JUE_ZHANG,
            JIAN_KE,
            QUAN_FENG_KE,
            MEN_FENG_KE,
            MEN_QIAN_QING,
            SI_GUI_YI,
            SHUANG_AN_KE,
            AN_GANG,
            DUAN_YAO_JIU,
            YAO_JIU_KE,
            MING_GANG,
            QUE_YI_MEN,
            WU_ZI,
            BIAN_ZHANG,
            KAN_ZHANG,
            DAN_DIAO_JIANG,
            ZI_MO,
            HUA_PAI);
        
        SAN_AN_KE.setNext(
            DA_YU_WU,
            XIAO_YU_WU,
            SAN_FENG_KE,
            TUI_BU_DAO,
            SAN_SE_SAN_JIE_GAO,
            MIAO_SHOU_HUI_CHUN,
            HAI_DI_LAO_YUE,
            GANG_SHANG_KAI_HUA,
            QIANG_GANG_HU,
            PENG_PENG_HU,
            HUN_YI_SE,
            WU_MEN_QI,
            SHUANG_AN_GANG,
            SHUANG_JIAN_KE,
            QUAN_DAI_YAO,
            BU_QIU_REN,
            HU_JUE_ZHANG,
            JIAN_KE,
            QUAN_FENG_KE,
            MEN_FENG_KE,
            MEN_QIAN_QING,
            SI_GUI_YI,
            SHUANG_TONG_KE,
            AN_GANG,
            DUAN_YAO_JIU,
            YAO_JIU_KE,
            MING_GANG,
            QUE_YI_MEN,
            WU_ZI,
            BIAN_ZHANG,
            KAN_ZHANG,
            DAN_DIAO_JIANG,
            ZI_MO,
            HUA_PAI);
        
        QUAN_BU_KAO.setNext(
            ZU_HE_LONG,
            MIAO_SHOU_HUI_CHUN,
            HAI_DI_LAO_YUE,
            QIANG_GANG_HU,
            HU_JUE_ZHANG,
            ZI_MO,
            HUA_PAI);
        
        ZU_HE_LONG.setNext(
            MIAO_SHOU_HUI_CHUN,
            HAI_DI_LAO_YUE,
            GANG_SHANG_KAI_HUA,
            QIANG_GANG_HU,
            WU_MEN_QI,
            BU_QIU_REN,
            HU_JUE_ZHANG,
            JIAN_KE,
            QUAN_FENG_KE,
            MEN_FENG_KE,
            MEN_QIAN_QING,
            SI_GUI_YI,
            AN_GANG,
            YAO_JIU_KE,
            MING_GANG,
            QUE_YI_MEN,
            WU_ZI,
            BIAN_ZHANG,
            KAN_ZHANG,
            DAN_DIAO_JIANG,
            ZI_MO,
            HUA_PAI);
        
        DA_YU_WU.setNext(
            TUI_BU_DAO,
            SAN_SE_SAN_JIE_GAO,
            SAN_SE_SAN_TONG_SHUN,
            MIAO_SHOU_HUI_CHUN,
            HAI_DI_LAO_YUE,
            GANG_SHANG_KAI_HUA,
            QIANG_GANG_HU,
            PENG_PENG_HU,
            QUAN_QIU_REN,
            SHUANG_AN_GANG,
            QUAN_DAI_YAO,
            BU_QIU_REN,
            SHUANG_MING_GANG,
            HU_JUE_ZHANG,
            MEN_QIAN_QING,
            PING_HU,
            SI_GUI_YI,
            SHUANG_TONG_KE,
            SHUANG_AN_KE,
            AN_GANG,
            DUAN_YAO_JIU,
            YI_BAN_GAO,
            XI_XIANG_FENG,
            YAO_JIU_KE,
            MING_GANG,
            QUE_YI_MEN,
            BIAN_ZHANG,
            KAN_ZHANG,
            DAN_DIAO_JIANG,
            ZI_MO,
            HUA_PAI);
        
        XIAO_YU_WU.setNext(
            TUI_BU_DAO,
            SAN_SE_SAN_JIE_GAO,
            SAN_SE_SAN_TONG_SHUN,
            MIAO_SHOU_HUI_CHUN,
            HAI_DI_LAO_YUE,
            GANG_SHANG_KAI_HUA,
            QIANG_GANG_HU,
            PENG_PENG_HU,
            QUAN_QIU_REN,
            SHUANG_AN_GANG,
            QUAN_DAI_YAO,
            BU_QIU_REN,
            SHUANG_MING_GANG,
            HU_JUE_ZHANG,
            MEN_QIAN_QING,
            PING_HU,
            SI_GUI_YI,
            SHUANG_TONG_KE,
            SHUANG_AN_KE,
            AN_GANG,
            DUAN_YAO_JIU,
            YI_BAN_GAO,
            XI_XIANG_FENG,
            YAO_JIU_KE,
            MING_GANG,
            QUE_YI_MEN,
            BIAN_ZHANG,
            KAN_ZHANG,
            DAN_DIAO_JIANG,
            ZI_MO,
            HUA_PAI);
        
        SAN_FENG_KE.setNext(
            MIAO_SHOU_HUI_CHUN,
            HAI_DI_LAO_YUE,
            GANG_SHANG_KAI_HUA,
            QIANG_GANG_HU,
            PENG_PENG_HU,
            HUN_YI_SE,
            QUAN_QIU_REN,
            SHUANG_AN_GANG,
            QUAN_DAI_YAO,
            BU_QIU_REN,
            SHUANG_MING_GANG,
            HU_JUE_ZHANG,
            JIAN_KE,
            QUAN_FENG_KE,//TODO 算不算？
            MEN_FENG_KE,//TODO 算不算？
            MEN_QIAN_QING,
            SHUANG_AN_KE,
            AN_GANG,
            YAO_JIU_KE, // TODO 是否不能算上三风刻里的幺九刻，只算别的19的
            MING_GANG,
            QUE_YI_MEN,
            BIAN_ZHANG,
            KAN_ZHANG,
            DAN_DIAO_JIANG,
            ZI_MO,
            HUA_PAI);
        
        HUA_LONG.setNext(
            MIAO_SHOU_HUI_CHUN,
            HAI_DI_LAO_YUE,
            GANG_SHANG_KAI_HUA,
            QIANG_GANG_HU,
            WU_MEN_QI,
            QUAN_QIU_REN,
            BU_QIU_REN,
            HU_JUE_ZHANG,
            JIAN_KE,
            QUAN_FENG_KE,
            MEN_FENG_KE,
            MEN_QIAN_QING,
            PING_HU,
            SI_GUI_YI,
            AN_GANG,
            YI_BAN_GAO,
            XI_XIANG_FENG,
            //LIAN_LIU, // 花龙时，喜相逢、连六、老少副三者只要有一种存在，则必然会共存另外两种中的一种，所以这儿只判断喜相逢一种
            //LAO_SHAO_FU,
            YAO_JIU_KE,
            MING_GANG,
            WU_ZI,
            BIAN_ZHANG,
            KAN_ZHANG,
            DAN_DIAO_JIANG,
            ZI_MO,
            HUA_PAI);
        
        TUI_BU_DAO.setNext(
            MIAO_SHOU_HUI_CHUN,
            HAI_DI_LAO_YUE,
            GANG_SHANG_KAI_HUA,
            QIANG_GANG_HU,
            PENG_PENG_HU,
            HUN_YI_SE,
            QUAN_QIU_REN,
            SHUANG_AN_GANG,
            QUAN_DAI_YAO,
            BU_QIU_REN,
            SHUANG_MING_GANG,
            HU_JUE_ZHANG,
            JIAN_KE,
            MEN_QIAN_QING,
            PING_HU,
            SI_GUI_YI,
            SHUANG_TONG_KE,
            SHUANG_AN_KE,
            AN_GANG,
            DUAN_YAO_JIU,
            YI_BAN_GAO,
            YAO_JIU_KE,
            MING_GANG,
            BIAN_ZHANG,
            KAN_ZHANG,
            DAN_DIAO_JIANG,
            ZI_MO,
            HUA_PAI);
        
        SAN_SE_SAN_JIE_GAO.setNext(
            MIAO_SHOU_HUI_CHUN,
            HAI_DI_LAO_YUE,
            GANG_SHANG_KAI_HUA,
            QIANG_GANG_HU,
            PENG_PENG_HU,
            WU_MEN_QI,
            QUAN_QIU_REN,
            SHUANG_AN_GANG,
            BU_QIU_REN,
            SHUANG_MING_GANG,
            HU_JUE_ZHANG,
            JIAN_KE,
            QUAN_FENG_KE,
            MEN_FENG_KE,
            MEN_QIAN_QING,
            SI_GUI_YI,
            SHUANG_TONG_KE,
            SHUANG_AN_KE,
            AN_GANG,
            DUAN_YAO_JIU,
            YAO_JIU_KE,
            MING_GANG,
            WU_ZI,
            BIAN_ZHANG,
            KAN_ZHANG,
            DAN_DIAO_JIANG,
            ZI_MO,
            HUA_PAI);
        
        SAN_SE_SAN_TONG_SHUN.setNext(
            MIAO_SHOU_HUI_CHUN,
            HAI_DI_LAO_YUE,
            GANG_SHANG_KAI_HUA,
            QIANG_GANG_HU,
            WU_MEN_QI,
            QUAN_QIU_REN,
            QUAN_DAI_YAO,
            BU_QIU_REN,
            HU_JUE_ZHANG,
            JIAN_KE,
            QUAN_FENG_KE,
            MEN_FENG_KE,
            MEN_QIAN_QING,
            PING_HU,
            SI_GUI_YI,
            AN_GANG,
            DUAN_YAO_JIU,
            YI_BAN_GAO,
            LIAN_LIU,
            LAO_SHAO_FU,
            YAO_JIU_KE,
            MING_GANG,
            WU_ZI,
            BIAN_ZHANG,
            KAN_ZHANG,
            DAN_DIAO_JIANG,
            ZI_MO,
            HUA_PAI);
        
        MIAO_SHOU_HUI_CHUN.setNext(
            GANG_SHANG_KAI_HUA,
            PENG_PENG_HU,
            HUN_YI_SE,
            SAN_SE_SAN_BU_GAO,
            WU_MEN_QI,
            SHUANG_AN_GANG,
            SHUANG_JIAN_KE,
            QUAN_DAI_YAO,
            BU_QIU_REN,
            SHUANG_MING_GANG,
            HU_JUE_ZHANG,
            JIAN_KE,
            QUAN_FENG_KE,
            MEN_FENG_KE,
            PING_HU,
            SI_GUI_YI,
            SHUANG_TONG_KE,
            SHUANG_AN_KE,
            AN_GANG,
            DUAN_YAO_JIU,
            YI_BAN_GAO,
            XI_XIANG_FENG,
            LIAN_LIU,
            LAO_SHAO_FU,
            YAO_JIU_KE,
            MING_GANG,
            QUE_YI_MEN,
            WU_ZI,
            BIAN_ZHANG,
            KAN_ZHANG,
            DAN_DIAO_JIANG,
            HUA_PAI);
        
        HAI_DI_LAO_YUE.setNext(
            QIANG_GANG_HU, // TODO
            PENG_PENG_HU,
            HUN_YI_SE,
            SAN_SE_SAN_BU_GAO,
            WU_MEN_QI,
            QUAN_QIU_REN,
            SHUANG_AN_GANG,
            SHUANG_JIAN_KE,
            QUAN_DAI_YAO,
            SHUANG_MING_GANG,
            HU_JUE_ZHANG,
            JIAN_KE,
            QUAN_FENG_KE,
            MEN_FENG_KE,
            MEN_QIAN_QING,
            PING_HU,
            SI_GUI_YI,
            SHUANG_TONG_KE,
            SHUANG_AN_KE,
            AN_GANG,
            DUAN_YAO_JIU,
            YI_BAN_GAO,
            XI_XIANG_FENG,
            LIAN_LIU,
            LAO_SHAO_FU,
            YAO_JIU_KE,
            MING_GANG,
            QUE_YI_MEN,
            WU_ZI,
            BIAN_ZHANG,
            KAN_ZHANG,
            DAN_DIAO_JIANG,
            HUA_PAI);
        
        GANG_SHANG_KAI_HUA.setNext(
            PENG_PENG_HU,
            HUN_YI_SE,
            SAN_SE_SAN_BU_GAO,
            WU_MEN_QI,
            SHUANG_AN_GANG,
            SHUANG_JIAN_KE,
            QUAN_DAI_YAO,
            BU_QIU_REN,
            SHUANG_MING_GANG,
            HU_JUE_ZHANG,
            JIAN_KE,
            QUAN_FENG_KE,
            MEN_FENG_KE,
            SI_GUI_YI,
            SHUANG_TONG_KE,
            SHUANG_AN_KE,
            AN_GANG,
            DUAN_YAO_JIU,
            YI_BAN_GAO,
            XI_XIANG_FENG,
            LIAN_LIU,
            LAO_SHAO_FU,
            YAO_JIU_KE,
            MING_GANG,
            QUE_YI_MEN,
            WU_ZI,
            BIAN_ZHANG,
            KAN_ZHANG,
            DAN_DIAO_JIANG,
            HUA_PAI);
        
        QIANG_GANG_HU.setNext(
            PENG_PENG_HU,
            HUN_YI_SE,
            SAN_SE_SAN_BU_GAO,
            WU_MEN_QI,
            QUAN_QIU_REN,
            SHUANG_AN_GANG,
            SHUANG_JIAN_KE,
            QUAN_DAI_YAO,
            SHUANG_MING_GANG,
            JIAN_KE,
            QUAN_FENG_KE,
            MEN_FENG_KE,
            MEN_QIAN_QING,
            PING_HU,
            SI_GUI_YI,
            SHUANG_TONG_KE,
            SHUANG_AN_KE,
            AN_GANG,
            DUAN_YAO_JIU,
            YI_BAN_GAO,
            XI_XIANG_FENG,
            LIAN_LIU,
            LAO_SHAO_FU,
            YAO_JIU_KE,
            MING_GANG,
            QUE_YI_MEN,
            WU_ZI,
            BIAN_ZHANG,
            KAN_ZHANG,
            HUA_PAI);
        
        PENG_PENG_HU.setNext(
            HUN_YI_SE,
            WU_MEN_QI,
            QUAN_QIU_REN,
            SHUANG_AN_GANG,
            SHUANG_JIAN_KE,
            //QUAN_DAI_YAO, // 如果碰碰和是全带幺，则必然是混幺九， 而混幺九不计碰碰和
            //BU_QIU_REN, // 如果碰碰和是不求人，则必然是四暗刻， 而四暗刻 不计碰碰和
            SHUANG_MING_GANG,
            JIAN_KE,
            QUAN_FENG_KE,
            MEN_FENG_KE,
            MEN_QIAN_QING, // 如果碰碰和是门前清，则必然是四暗刻或三暗刻， 而四暗刻 不计碰碰和，三暗刻可计
            SHUANG_TONG_KE,
            SHUANG_AN_KE,
            AN_GANG,
            DUAN_YAO_JIU,
            YAO_JIU_KE,
            MING_GANG,
            QUE_YI_MEN,
            WU_ZI,
            DAN_DIAO_JIANG,
            ZI_MO,
            HUA_PAI);
        
        HUN_YI_SE.setNext(
            QUAN_QIU_REN,
            SHUANG_AN_GANG,
            SHUANG_JIAN_KE,
            QUAN_DAI_YAO,
            BU_QIU_REN,
            SHUANG_MING_GANG,
            HU_JUE_ZHANG,
            JIAN_KE,
            QUAN_FENG_KE,
            MEN_FENG_KE,
            MEN_QIAN_QING,
            SI_GUI_YI,
            SHUANG_AN_KE,
            AN_GANG,
            DUAN_YAO_JIU,
            YI_BAN_GAO,
            LIAN_LIU,
            LAO_SHAO_FU,
            YAO_JIU_KE,
            MING_GANG,
            BIAN_ZHANG,
            KAN_ZHANG,
            DAN_DIAO_JIANG,
            ZI_MO,
            HUA_PAI);
        
        SAN_SE_SAN_BU_GAO.setNext(
            WU_MEN_QI,
            QUAN_QIU_REN,
            BU_QIU_REN,
            HU_JUE_ZHANG,
            JIAN_KE,
            QUAN_FENG_KE,
            MEN_FENG_KE,
            MEN_QIAN_QING,
            PING_HU,
            SI_GUI_YI,
            AN_GANG,
            DUAN_YAO_JIU,
            YI_BAN_GAO,
            XI_XIANG_FENG,
            LIAN_LIU,
            LAO_SHAO_FU,
            YAO_JIU_KE,
            MING_GANG,
            WU_ZI,
            BIAN_ZHANG,
            KAN_ZHANG,
            DAN_DIAO_JIANG,
            ZI_MO,
            HUA_PAI);
        
        WU_MEN_QI.setNext(
            QUAN_QIU_REN,
            SHUANG_AN_GANG,
            QUAN_DAI_YAO,
            BU_QIU_REN,
            SHUANG_MING_GANG,
            HU_JUE_ZHANG,
            JIAN_KE,
            QUAN_FENG_KE,
            MEN_FENG_KE,
            MEN_QIAN_QING,
            SI_GUI_YI, // 七对时
            SHUANG_TONG_KE,
            SHUANG_AN_KE,
            AN_GANG,
            XI_XIANG_FENG,
            YAO_JIU_KE,
            MING_GANG,
            BIAN_ZHANG,
            KAN_ZHANG,
            DAN_DIAO_JIANG,
            ZI_MO,
            HUA_PAI);
        
        QUAN_QIU_REN.setNext(
            SHUANG_JIAN_KE,
            QUAN_DAI_YAO,
            SHUANG_MING_GANG,
            JIAN_KE,
            QUAN_FENG_KE,
            MEN_FENG_KE,
            PING_HU,
            SI_GUI_YI,
            SHUANG_TONG_KE,
            DUAN_YAO_JIU,
            YI_BAN_GAO,
            XI_XIANG_FENG,
            LIAN_LIU,
            LAO_SHAO_FU,
            YAO_JIU_KE,
            MING_GANG,
            QUE_YI_MEN,
            WU_ZI,
            BIAN_ZHANG,
            KAN_ZHANG,
            HUA_PAI);
        
        SHUANG_AN_GANG.setNext(
            SHUANG_JIAN_KE,
            QUAN_DAI_YAO,
            BU_QIU_REN,
            HU_JUE_ZHANG,
            JIAN_KE,
            QUAN_FENG_KE,
            MEN_FENG_KE,
            MEN_QIAN_QING,
            SI_GUI_YI,
            SHUANG_TONG_KE,
            DUAN_YAO_JIU,
            YI_BAN_GAO,
            XI_XIANG_FENG,
            LIAN_LIU,
            LAO_SHAO_FU,
            YAO_JIU_KE,
            QUE_YI_MEN,
            WU_ZI,
            BIAN_ZHANG,
            KAN_ZHANG,
            DAN_DIAO_JIANG,
            ZI_MO,
            HUA_PAI);
        
        SHUANG_JIAN_KE.setNext(
            QUAN_DAI_YAO,
            BU_QIU_REN,
            SHUANG_MING_GANG,
            HU_JUE_ZHANG,
            QUAN_FENG_KE,
            MEN_FENG_KE,
            MEN_QIAN_QING,
            SI_GUI_YI,
            SHUANG_TONG_KE,
            SHUANG_AN_KE,
            AN_GANG,
            YI_BAN_GAO,
            XI_XIANG_FENG,
            LIAN_LIU,
            LAO_SHAO_FU,
            YAO_JIU_KE,//TODO 只能是19和不是门风、圈风的风刻
            MING_GANG,
            QUE_YI_MEN,
            BIAN_ZHANG,
            KAN_ZHANG,
            DAN_DIAO_JIANG,
            ZI_MO,
            HUA_PAI);
        
        QUAN_DAI_YAO.setNext(
            BU_QIU_REN,
            SHUANG_MING_GANG,
            HU_JUE_ZHANG,
            JIAN_KE,
            QUAN_FENG_KE,
            MEN_FENG_KE,
            MEN_QIAN_QING,
            PING_HU,
            SI_GUI_YI,
            SHUANG_TONG_KE,
            SHUANG_AN_KE,
            AN_GANG,
            YI_BAN_GAO,
            XI_XIANG_FENG,
            LAO_SHAO_FU,
            YAO_JIU_KE,
            MING_GANG,
            QUE_YI_MEN,
            WU_ZI,
            BIAN_ZHANG,
            KAN_ZHANG,
            DAN_DIAO_JIANG,
            ZI_MO,
            HUA_PAI);

        BU_QIU_REN.setNext(
            HU_JUE_ZHANG,
            JIAN_KE,
            QUAN_FENG_KE,
            MEN_FENG_KE,
            PING_HU,
            SI_GUI_YI,
            SHUANG_TONG_KE,
            SHUANG_AN_KE,
            AN_GANG,
            DUAN_YAO_JIU,
            YI_BAN_GAO,
            XI_XIANG_FENG,
            LIAN_LIU,
            LAO_SHAO_FU,
            YAO_JIU_KE,
            QUE_YI_MEN,
            WU_ZI,
            BIAN_ZHANG,
            KAN_ZHANG,
            DAN_DIAO_JIANG,
            HUA_PAI);

        SHUANG_MING_GANG.setNext(
            HU_JUE_ZHANG,
            JIAN_KE,
            QUAN_FENG_KE,
            MEN_FENG_KE,
            SI_GUI_YI,
            SHUANG_TONG_KE,
            SHUANG_AN_KE,
            DUAN_YAO_JIU,
            YI_BAN_GAO,
            XI_XIANG_FENG,
            LIAN_LIU,
            LAO_SHAO_FU,
            YAO_JIU_KE,
            QUE_YI_MEN,
            WU_ZI,
            BIAN_ZHANG,
            KAN_ZHANG,
            DAN_DIAO_JIANG,
            ZI_MO,
            HUA_PAI);

        HU_JUE_ZHANG.setNext(
            JIAN_KE,
            QUAN_FENG_KE,
            MEN_FENG_KE,
            MEN_QIAN_QING,
            PING_HU,
            SI_GUI_YI,
            SHUANG_TONG_KE,
            SHUANG_AN_KE,
            AN_GANG,
            DUAN_YAO_JIU,
            YI_BAN_GAO,
            XI_XIANG_FENG,
            LIAN_LIU,
            LAO_SHAO_FU,
            YAO_JIU_KE,
            MING_GANG,
            QUE_YI_MEN,
            WU_ZI,
            BIAN_ZHANG,
            KAN_ZHANG,
            DAN_DIAO_JIANG,
            ZI_MO,
            HUA_PAI);

        JIAN_KE.setNext(
            QUAN_FENG_KE,
            MEN_FENG_KE,
            MEN_QIAN_QING,
            SI_GUI_YI,
            SHUANG_TONG_KE,
            SHUANG_AN_KE,
            AN_GANG,
            YI_BAN_GAO,
            XI_XIANG_FENG,
            LIAN_LIU,
            LAO_SHAO_FU,
            YAO_JIU_KE,
            MING_GANG,
            QUE_YI_MEN,
            BIAN_ZHANG,
            KAN_ZHANG,
            DAN_DIAO_JIANG,
            ZI_MO,
            HUA_PAI);

        QUAN_FENG_KE.setNext( //圈风门风相同时，网上说需要重复计算 TODO
            MEN_FENG_KE,
            MEN_QIAN_QING,
            SI_GUI_YI,
            SHUANG_TONG_KE,
            SHUANG_AN_KE,
            AN_GANG,
            YI_BAN_GAO,
            XI_XIANG_FENG,
            LIAN_LIU,
            LAO_SHAO_FU,
            YAO_JIU_KE,
            MING_GANG,
            QUE_YI_MEN,
            BIAN_ZHANG,
            KAN_ZHANG,
            DAN_DIAO_JIANG,
            ZI_MO,
            HUA_PAI);

        MEN_FENG_KE.setNext(
            MEN_QIAN_QING,
            SI_GUI_YI,
            SHUANG_TONG_KE,
            SHUANG_AN_KE,
            AN_GANG,
            YI_BAN_GAO,
            XI_XIANG_FENG,
            LIAN_LIU,
            LAO_SHAO_FU,
            YAO_JIU_KE,
            MING_GANG,
            QUE_YI_MEN,
            BIAN_ZHANG,
            KAN_ZHANG,
            DAN_DIAO_JIANG,
            ZI_MO,
            HUA_PAI);

        MEN_QIAN_QING.setNext(
            PING_HU,
            SI_GUI_YI,
            SHUANG_TONG_KE,
            SHUANG_AN_KE,
            AN_GANG,
            DUAN_YAO_JIU,
            YI_BAN_GAO,
            XI_XIANG_FENG,
            LIAN_LIU,
            LAO_SHAO_FU,
            YAO_JIU_KE,
            QUE_YI_MEN,
            WU_ZI,
            BIAN_ZHANG,
            KAN_ZHANG,
            DAN_DIAO_JIANG,
            HUA_PAI);

        PING_HU.setNext(
            DUAN_YAO_JIU,
            YI_BAN_GAO,
            XI_XIANG_FENG,
            LIAN_LIU,
            LAO_SHAO_FU,
            QUE_YI_MEN,
            //WU_ZI, //按平和的规则，一定无字
            BIAN_ZHANG,
            KAN_ZHANG,
            DAN_DIAO_JIANG,
            ZI_MO,
            HUA_PAI);

        SI_GUI_YI.setNext(
            SHUANG_TONG_KE,
            SHUANG_AN_KE,
            AN_GANG,
            DUAN_YAO_JIU,
            YI_BAN_GAO,
            XI_XIANG_FENG,
            LIAN_LIU,
            LAO_SHAO_FU,
            YAO_JIU_KE,
            MING_GANG,
            QUE_YI_MEN,
            WU_ZI,
            BIAN_ZHANG,
            KAN_ZHANG,
            DAN_DIAO_JIANG,
            ZI_MO,
            HUA_PAI);

        SHUANG_TONG_KE.setNext(
            SHUANG_AN_KE,
            AN_GANG,
            DUAN_YAO_JIU,
            YI_BAN_GAO,
            XI_XIANG_FENG,
            LIAN_LIU,
            LAO_SHAO_FU,
            YAO_JIU_KE,
            MING_GANG,
            QUE_YI_MEN,
            WU_ZI,
            BIAN_ZHANG,
            KAN_ZHANG,
            DAN_DIAO_JIANG,
            ZI_MO,
            HUA_PAI);

        SHUANG_AN_KE.setNext(
            AN_GANG,
            DUAN_YAO_JIU,
            YI_BAN_GAO,
            XI_XIANG_FENG,
            LIAN_LIU,
            LAO_SHAO_FU,
            YAO_JIU_KE,
            MING_GANG,
            QUE_YI_MEN,
            WU_ZI,
            BIAN_ZHANG,
            KAN_ZHANG,
            DAN_DIAO_JIANG,
            ZI_MO,
            HUA_PAI);

        AN_GANG.setNext(
            DUAN_YAO_JIU,
            YI_BAN_GAO,
            XI_XIANG_FENG,
            LIAN_LIU,
            LAO_SHAO_FU,
            YAO_JIU_KE,
            MING_GANG,
            QUE_YI_MEN,
            WU_ZI,
            BIAN_ZHANG,
            KAN_ZHANG,
            DAN_DIAO_JIANG,
            ZI_MO,
            HUA_PAI);

        DUAN_YAO_JIU.setNext(
            YI_BAN_GAO,
            XI_XIANG_FENG,
            LIAN_LIU,
            MING_GANG,
            QUE_YI_MEN,
            BIAN_ZHANG,
            KAN_ZHANG,
            DAN_DIAO_JIANG,
            ZI_MO,
            HUA_PAI);

        YI_BAN_GAO.setNext(
            XI_XIANG_FENG,
            LIAN_LIU,
            LAO_SHAO_FU,
            YAO_JIU_KE,
            MING_GANG,
            QUE_YI_MEN,
            WU_ZI,
            BIAN_ZHANG,
            KAN_ZHANG,
            DAN_DIAO_JIANG,
            ZI_MO,
            HUA_PAI);

        XI_XIANG_FENG.setNext(
            LIAN_LIU,
            LAO_SHAO_FU,
            YAO_JIU_KE,
            MING_GANG,
            QUE_YI_MEN,
            WU_ZI,
            BIAN_ZHANG,
            KAN_ZHANG,
            DAN_DIAO_JIANG,
            ZI_MO,
            HUA_PAI);

        LIAN_LIU.setNext(
            LAO_SHAO_FU,
            YAO_JIU_KE,
            MING_GANG,
            QUE_YI_MEN,
            WU_ZI,
            BIAN_ZHANG,
            KAN_ZHANG,
            DAN_DIAO_JIANG,
            ZI_MO,
            HUA_PAI);

        LAO_SHAO_FU.setNext(
            YAO_JIU_KE,
            MING_GANG,
            QUE_YI_MEN,
            WU_ZI,
            BIAN_ZHANG,
            KAN_ZHANG,
            DAN_DIAO_JIANG,
            ZI_MO,
            HUA_PAI);

        YAO_JIU_KE.setNext(
            MING_GANG,
            QUE_YI_MEN,
            WU_ZI,
            BIAN_ZHANG,
            KAN_ZHANG,
            DAN_DIAO_JIANG,
            ZI_MO,
            HUA_PAI);

        MING_GANG.setNext(
            QUE_YI_MEN,
            WU_ZI,
            BIAN_ZHANG,
            KAN_ZHANG,
            DAN_DIAO_JIANG,
            ZI_MO,
            HUA_PAI);

        QUE_YI_MEN.setNext(
            WU_ZI,
            BIAN_ZHANG,
            KAN_ZHANG,
            DAN_DIAO_JIANG,
            ZI_MO,
            HUA_PAI);

        WU_ZI.setNext(
            BIAN_ZHANG,
            KAN_ZHANG,
            DAN_DIAO_JIANG,
            ZI_MO,
            HUA_PAI);

        BIAN_ZHANG.setNext(
            ZI_MO,
            HUA_PAI);

        KAN_ZHANG.setNext(
            ZI_MO,
            HUA_PAI);

        DAN_DIAO_JIANG.setNext(
            ZI_MO,
            HUA_PAI);

        ZI_MO.setNext(HUA_PAI);

        WU_FAN_HU.setNext(HUA_PAI);
        
        HUA_PAI.setNext();

        SPECIALS = new GbPaixing[] { SHI_SAN_YAO,
                                     LIAN_QI_DUI,
                                     QI_DUI,
                                     QI_XING_BU_KAO,
                                     QUAN_BU_KAO,
                                     ZU_HE_LONG };
    }
    
    private static final GbPaixing[] SPECIALS;
    private static final int[] YAO_JIU_ZI = { 11, 19, 21, 29, 31, 39, 41, 42, 43, 44, 51, 52, 53 };

    private String      name;
    private int         fanshu;
    private GbPaixing[] next;
    private boolean     isSpecial;
    
    GbPaixing(String name, int fanshu, boolean isSpecial) {
        this.name = name;
        this.fanshu = fanshu;
        this.isSpecial = isSpecial;
    }

    GbPaixing(String name, int fanshu) {
        this(name, fanshu, false);
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public int getFanshu() {
        return fanshu;
    }

    @Override
    public GbPaixing[] next() {
        return next;
    }

    @Override
    public boolean isSpecial() {
        return isSpecial;
    }
    
    /**
     * 国标牌型的字符串表示。形式为：名称(番数)
     * 
     * @return 国标牌型字符串
     */
    @Override
    public String toString() {
        return name + "(" + fanshu + ")";
    }

    /**
     * 得到特殊牌型(不符合33332形式的牌型)
     * 
     * @return 特殊牌型
     */
    public static GbPaixing[] getSpecials() {
        return SPECIALS;
    }

    /*
     * 设置当符合此牌型后还需要判断的牌型
     */
    private void setNext(GbPaixing... next) {
        this.next = next;
    }
    
    private static final boolean isPeng(int type) {
        return type == PENG_XIAJIA || type == PENG_DUIJIA || type == PENG_SHANGJIA;
    }
    
    private static boolean isMinggang(int type) {
        return type == GANG_XIAJIA || type == GANG_DUIJIA || type == GANG_SHANGJIA;
    }
    
    private static boolean isAngang(int type) {
        return type == GANG_AN;
    }
    
    private static boolean isGang(int type) {
        return isMinggang(type) || isAngang(type);
    }
    
    /*
     * 风箭满足全不靠形式时，总的张数
     */
    private static int quanBukaoCountFengJian(int[] data) {
        int count = 0;
        int paiCount = 0;
        int p = 41;
        for (; p <= 44; p++) {
            paiCount = data[p];
            if (paiCount == 1)
                count += 1;
            else if (paiCount != 0)
                return 0;
        }
        for (p = 51; p <= 53; p++) {
            paiCount = data[p];
            if (paiCount == 1)
                count += 1;
            else if (paiCount != 0)
                return 0;
        }
        return count;
    }

    /*
     * 万条饼满足全不靠形式时，总的张数
     */
    private static int bukaoCountWanTiaoBing(int[] data) {
        int count = 0;
        int w = -1;
        for (int p = 11; p <= 19; p++) {
            int paiCount = data[p];
            if (paiCount > 1)
                return 0;
            if (paiCount == 1) {
                int type = (p - 10) % 3;
                if (w == -1) {
                    w = type;
                    count++;
                } else if (type == w)
                    count++;
                else
                    return 0;
            }
        }
        
        int t = -1;
        for (int p = 21; p <= 29; p++) {
            int paiCount = data[p];
            if (paiCount > 1)
                return 0;
            if (paiCount == 1) {
                int type = (p - 20) % 3;
                if (type == w)
                    return 0;
                if (t == -1) {
                    t = type;
                    count++;
                } else if (type == t)
                    count++;
                else
                    return 0;
            }
        }
        
        int b = -1;
        for (int p = 31; p <= 39; p++) {
            int paiCount = data[p];
            if (paiCount > 1)
                return 0;
            if (paiCount == 1) {
                int type = (p - 30) % 3;
                if (type == w || type == t)
                    return 0;
                if (b == -1) {
                    b = type;
                    count++;
                } else if (type == b)
                    count++;
                else
                    return 0;
            }
        }
        
        return count;
    }
    
}
